Command Network
题目大意:给出一个有向图,给出n个顶点的坐标,以及每条边连接的顶点,指定一个起点,找到一个方案,使得从这个点到其他所有点的路径的权值和最小,求最小权值
/* 最小树形图模板题 对缩点及其下面几个部分的解释: vis相当于一个bool数组,标记某个点是否被访问过,因为每一次的for都要用vis,每一次赋值i可以避免memset false,快 pre记录环上前驱,缩点之后点的编号会有所改变,用col记录 */ #include<iostream> #include<cstring> #include<cstdio> #include<cmath> #define maxn 110 #define INF 2e9 using namespace std; int n,m,pre[maxn],vis[maxn],col[maxn],num; struct node{ int from,to; double v; }e[10010]; double x[maxn],y[maxn],in[maxn]; double zhuliu(){ int tot=n,root=1,cirnum,to; double ans=0; while(1){ for(int i=1;i<=tot;i++)in[i]=INF; for(int i=1;i<=m;i++)//枚举每条边 if(e[i].v<in[e[i].to]&&e[i].from!=e[i].to){ pre[e[i].to]=e[i].from; in[e[i].to]=e[i].v;//in[i]表示指向i最小的边权 } for(int i=1;i<=tot;i++)//判断能否组成树形图 if(i!=root&&in[i]==INF)return -1; cirnum=0; memset(vis,0,sizeof(vis)); memset(col,0,sizeof(col)); in[root]=0; for(int i=1;i<=tot;i++){//缩点 ans+=in[i]; to=i; while(vis[to]!=i&&!col[to]&&to!=root) {vis[to]=i;to=pre[to];} if(to!=root&&!col[to]){ cirnum++; for(int j=pre[to];j!=to;j=pre[j]) col[j]=cirnum; col[to]=cirnum; } } if(!cirnum)break; for(int i=1;i<=tot;i++) if(!col[i])col[i]=++cirnum; for(int i=1;i<=m;i++){ to=e[i].to; e[i].from=col[e[i].from]; e[i].to=col[e[i].to]; if(e[i].from!=e[i].to)e[i].v-=in[to]; } tot=cirnum; root=col[root]; } return ans; } int main(){ double ans; while(scanf("%d%d",&n,&m)!=EOF){ for(int i=1;i<=n;i++)scanf("%lf%lf",&x[i],&y[i]); num=0; int a,b; for(int i=1;i<=m;i++){ scanf("%d%d",&a,&b); double dis=sqrt((x[a]-x[b])*(x[a]-x[b])+(y[a]-y[b])*(y[a]-y[b])); if(a!=b){ e[++num].to=b; e[num].from=a; e[num].v=dis; } } m=num; ans=zhuliu(); if(ans==-1)puts("poor snoopy"); else printf("%.2lf ",ans); } }