poj 3164
朱刘算法
步骤:
1、计算出每个点边权最小的边的权(如果除根以外有其他的点没有入边,则不存在最小树形图),并记下边的另一个端点(称其为这个点的前趋)
2、沿着每个点向上走,如果在走到根或环上的点之前,就遇到走过的点,那么就出现环了。将环上的点标记一下当前环的编号,并将环上的所有边的边权加在答案里。
3、如果在2中没有找到环,将当前图除了根以外对应的点的最小入边边权加在答案里,然后返回答案。
4、否则,将剩下的点标号,并标记为非环点,将所有边两端的点的编号换成对应环的编号,如果目标点是一个环,将边权减少目标点对应的环中的最小入边权。
复杂度:最坏O(N^3)
1 #include <cstdio> 2 #include <cmath> 3 #include <vector> 4 #define oo 1e20 5 #define N 110 6 #define M 10100 7 using namespace std; 8 9 struct Edge { 10 int u, v; 11 double w; 12 Edge(){} 13 Edge( int u, int v, double w ):u(u),v(v),w(w){} 14 }; 15 16 int n, m; 17 double pts[N][2]; 18 int idx[N], vis[N], pre[N], inc[N]; 19 double inw[N]; 20 Edge edge[M]; 21 22 double getdis( int u, int v ) { 23 int dx = pts[u][0]-pts[v][0]; 24 int dy = pts[u][1]-pts[v][1]; 25 return sqrt(dx*dx+dy*dy); 26 } 27 double diricted_mst( int root ) { 28 double rt = 0.0; 29 while(1) { 30 //--- 31 for( int i=1; i<=n; i++ ) 32 inw[i] = oo; 33 for( int i=0; i<m; i++ ) { 34 Edge &e = edge[i]; 35 if( e.u==e.v ) continue; 36 if( inw[e.v]>e.w ) { 37 inw[e.v]=e.w; 38 pre[e.v]=e.u; 39 } 40 } 41 for( int i=1; i<=n; i++ ) 42 if( inw[i]==oo && i!=root ) 43 return -1.0; 44 //--- 45 for( int i=1; i<=n; i++ ) 46 vis[i] = idx[i] = 0; 47 int cnt = 0; 48 for( int u=1,v,s; u<=n; u++ ) { 49 if( u==root ) continue; 50 for( v=pre[u]; v!=root && !idx[v] && vis[v]!=u; v=pre[v] ) 51 vis[v] = u; 52 if( v==root || idx[v] ) continue; 53 cnt++; 54 s = v; 55 for( v=pre[s]; v!=s; v=pre[v] ) { 56 inc[v] = true; 57 idx[v] = cnt; 58 rt += inw[v]; 59 } 60 inc[s] = true; 61 idx[s] = cnt; 62 rt += inw[s]; 63 } 64 if( cnt==0 ) { 65 for( int u=1; u<=n; u++ ) 66 if( u!=root ) 67 rt += inw[u]; 68 break; 69 } 70 for( int u=1; u<=n; u++ ) 71 if( !idx[u] ) { 72 inc[u] = false; 73 idx[u]=++cnt; 74 } 75 //--- 76 for( int i=0; i<m; i++ ) { 77 Edge &e=edge[i]; 78 if( inc[e.v] ) e.w-=inw[e.v]; 79 e.u = idx[e.u]; 80 e.v = idx[e.v]; 81 } 82 root = idx[root]; 83 n = cnt; 84 } 85 return rt; 86 } 87 int main() { 88 while(~scanf("%d%d",&n,&m)) { 89 for( int i=1; i<=n; i++ ) 90 scanf( "%lf%lf", &pts[i][0], &pts[i][1] ); 91 for( int i=0,u,v; i<m; i++ ) { 92 scanf( "%d%d", &u, &v ); 93 edge[i] = Edge(u,v,getdis(u,v)); 94 } 95 double ans = diricted_mst(1); 96 if( ans<0.0 ) printf( "poor snoopy\n" ); 97 else printf( "%.2f\n", ans ); 98 } 99 }