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
" );
97         else printf( "%.2f
", ans );
98     }
99 }
View Code
原文地址:https://www.cnblogs.com/idy002/p/4450617.html