USACO 4.1 Fence Loops(无向图中的最小环)
这个算是一个模版题,不过以前没见过。。。我冥思苦想,想爆搜,却知从何搜起,然后突然想到以前做过一个最小环的,关于某一个点的最小环两遍spfa,搞定。然后我啪啪开写,先自己把数据转化为点,然后离散一下。。。写了老长,还选择比较好写的floyd,样例过不了,意识到发现这样写不对啊。。。
从网上找到了做法。。
1:朴素的求最小环的方法做E遍Dijkstra,枚举每条边e(i,j),删去边e(i,j)之后,求i到j的最短路经,然后再加上该边求最小值便得到的了最小环,时间复杂度为O(E*(N^2))。
2:改进的floyd算法,求出任意两点之间的最短路的同时,求出最小环。
我用的是后者,因为图都建好了。。。不能白写了啊。。。证明详细,还是去搜网上的资料把。
1 /* 2 ID: cuizhe 3 LANG: C++ 4 TASK: fence6 5 */ 6 #include <iostream> 7 #include <cstdio> 8 #include <cstring> 9 #include <cmath> 10 #include <algorithm> 11 #include <map> 12 #include <string> 13 #include <vector> 14 using namespace std; 15 #define N 10000000 16 int o[301]; 17 int dp[201][201],g[201][201]; 18 struct point 19 { 20 int x,y,dis; 21 int nl,nr; 22 int L[9],R[9]; 23 } p[101]; 24 int pfind(int x,int key) 25 { 26 int i; 27 for(i = 1; i <= p[key].nl; i ++) 28 { 29 if(p[key].L[i] == x) 30 return p[key].x; 31 } 32 for(i = 1; i <= p[key].nr; i ++) 33 { 34 if(p[key].R[i] == x) 35 return p[key].y; 36 } 37 return 200; 38 } 39 int build(int n)//建图 40 { 41 int i,j,r,c,num; 42 for(i = 1; i <= n; i ++) 43 { 44 o[p[i].x] = 1; 45 o[p[i].y] = 1; 46 } 47 num = 1; 48 for(i = 1; i <= 2*n; i ++) 49 { 50 if(o[i]) 51 o[i] = num ++; 52 } 53 for(i = 1; i <= num-1; i ++) 54 { 55 for(j = 1; j <= num-1; j ++) 56 { 57 g[i][j] = dp[i][j] = N; 58 } 59 g[i][j] = dp[i][i] = 0; 60 } 61 for(i = 1; i <= n; i ++) 62 { 63 if(o[p[i].x] > o[p[i].y]) 64 { 65 r = o[p[i].x]; 66 c = o[p[i].y]; 67 } 68 else 69 { 70 c = o[p[i].x]; 71 r = o[p[i].y]; 72 } 73 g[r][c] = dp[r][c] = min(dp[r][c],p[i].dis); 74 g[c][r] = dp[c][r] = min(dp[c][r],p[i].dis); 75 } 76 return num-1; 77 } 78 int main() 79 { 80 int i,j,n,num,k,minz; 81 freopen("fence6.in","r",stdin); 82 freopen("fence6.out","w",stdout); 83 scanf("%d",&n); 84 for(i = 1; i <= n; i ++) 85 { 86 p[i].x = 2*i-1; 87 p[i].y = 2*i; 88 } 89 for(i = 1; i <= n; i ++) 90 { 91 scanf("%d",&num); 92 scanf("%d%d%d",&p[num].dis,&p[num].nl,&p[num].nr); 93 for(j = 1; j <= p[num].nl; j ++) 94 scanf("%d",&p[num].L[j]); 95 for(j = 1; j <= p[num].nr; j ++) 96 scanf("%d",&p[num].R[j]); 97 } 98 for(i = 1; i <= n; i ++) 99 { 100 for(j = 1; j <= p[i].nl; j ++) 101 { 102 p[i].x = min(p[i].x,pfind(i,p[i].L[j])); 103 } 104 for(j = 1; j <= p[num].nr; j ++) 105 { 106 p[i].y = min(p[i].y,pfind(i,p[i].R[j])); 107 } 108 } 109 n = build(n); 110 minz = N; 111 for(i = 1; i <= n; i ++)//求最小环 112 { 113 for(j = 1; j <= i-1; j ++) 114 for(k = j+1; k <= i-1; k ++) 115 minz = min(minz,dp[j][k] + g[j][i] + g[i][k]); 116 for(j = 1; j <= n; j ++) 117 for(k = 1; k <= n; k ++) 118 dp[j][k] = min(dp[j][k],dp[j][i]+dp[i][k]); 119 } 120 printf("%d\n",minz); 121 return 0; 122 }