poj 3264 Command Network(最小树形图)
有一副有向图,要求从根节点起能访问到所有的结点,且路径最短。即求最小树形图。
算法位朱刘算法,
裸的最小树形图,用朱—刘算法解决,具体实现过程如下:算法一开始先判断从固定根开始是否可达所有原图中的点,若不可,则一定不存在最小树形图。这一步是一个很随便的搜索,写多搓都行,不加废话。第二步,遍历所有的边,从中找出除根结点外各点的最小入边,累加权值,构成新图。接着判断该图是否存在环。若不存在,则该图便是所求最小树型图,当前权为最小权。否则对环缩点,然后回到第二步继续判断。简化就是三个过程:找边—>找环—>缩点;
#include<cstdio> #include<cmath> #include<algorithm> #include<cstring> using namespace std; const double inf=200000000; const int maxn = 110; typedef double type; struct Point{ double x,y; }p[maxn]; struct Node{ int u,v; type w; }node[maxn*maxn]; int pre[maxn],id[maxn],vis[maxn],n,m; type in[maxn]; double dis(Point a,Point b){ return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); } type mst(int root,int v,int e){ type ret=0; while(true){ for(int i=0;i<v;i++) in[i]=inf; for(int i=0;i<e;i++){ int u=node[i].u; int v=node[i].v; if(node[i].w<in[v] && u!=v){ pre[v]=u; in[v]=node[i].w; } } for(int i=0;i<v;i++){ if(i==root) continue; if(in[i]==inf) return -1; } int cnt=0; memset(id,-1,sizeof(id)); memset(vis,-1,sizeof(vis)); in[root] =0; for(int i=0;i<v;i++) { ret+=in[i]; int V=i; while(vis[V] !=i && id[V] ==-1 && V!=root){ vis[V]=i; V=pre[V]; } if(V!=root && id[V]==-1){ for(int u=pre[V];u!=V;u=pre[u]) id[u]=cnt; id[V]=cnt++; } } if(cnt==0)break; for(int i=0;i<v;i++){ if(id[i]==-1) id[i]=cnt++; } for(int i=0;i<e;i++){ int u=node[i].u; int v=node[i].v; node[i].u=id[u]; node[i].v=id[v]; if(id[u] != id[v]) node[i].w-=in[v]; } v=cnt; root=id[root]; } return ret; } int main(){ while(scanf("%d%d",&n,&m)!=EOF){ for(int i=0;i<n;i++){ scanf("%lf%lf",&p[i].x,&p[i].y); } for(int i=0;i<m;i++){ scanf("%d%d",&node[i].u,&node[i].v); node[i].u--; node[i].v--; if(node[i].u!=node[i].v) node[i].w=dis(p[node[i].u],p[node[i].v]); else node[i].w=inf; } type ans=mst(0,n,m); if(ans==-1) printf("poor snoopy\n"); else printf("%.2f\n",ans); } return 0; }