poj 3164(最小树形图模板)
题目链接:http://poj.org/problem?id=3164
详细可以看这里:http://www.cnblogs.com/vongang/archive/2012/07/18/2596851.html
我没怎么看懂 = =,姑且做个模板了。。
题意就是给n个点,m条单向边,并且已知根节点,求有向图的最小生成树。
#include <stdio.h> #include <iostream> #include <string.h> #include <algorithm> #include <math.h> using namespace std; typedef double type; const int N = 105; const int M = 10005; const type INF = 999999999; struct Point { int x,y; } p[N]; struct Edge { int u,v; double cost; } edge[M]; ///最小树形图算法 type IN[N]; int vis[N],pre[N],id[N]; type Directed_MST(int root,int n,int m) ///n为点数,m为边数 { type cost = 0; while(true) { ///找最小入边 for(int i=0; i<n; i++) IN[i] = INF; for(int i=0; i<m; i++) { int u = edge[i].u,v = edge[i].v; if(edge[i].cost<IN[v]&&u!=v) { pre[v]=u,IN[v]=edge[i].cost; } } for(int i=0; i<n; i++) ///判断是否有最小树形图(除了root之外还存在点没有入边) { 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<n; i++) { cost +=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<n; i++) { if(id[i]==-1) id[i]=cnt++; } ///建立新图 for(int i = 0; i < m; i++) { int u = edge[i].u; int v = edge[i].v; edge[i].u = id[u]; edge[i].v = id[v]; if(id[u] != id[v]) edge[i].cost -= IN[v]; } n = cnt; root = id[root]; } return cost; } double dis(Point a,Point b) { return sqrt(1.0*((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y))); } int main() { int n,m; while(scanf("%d%d",&n,&m)!=EOF) { for(int i=0; i<n; i++) { scanf("%d%d",&p[i].x,&p[i].y); } for(int i=0; i<m; i++) { scanf("%d%d",&edge[i].u,&edge[i].v); edge[i].u--,edge[i].v--; if(edge[i].u==edge[i].v) edge[i].cost = INF; ///除去自环 else edge[i].cost = dis(p[edge[i].u],p[edge[i].v]); } double cost = Directed_MST(0,n,m); if(cost==-1) printf("poor snoopy\n"); else printf("%.2lf\n",cost); } }