【HDU3870 Catch the Theves】 最小割与最短路模型进行转换
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3870
题目大意:O(-1).
解题思路:开始直接构图,套Dinic()模板,悲剧的TLE。再认真看看题,n为400,也就是有400*400个点,边大概是节点的4倍大小,明显最大流会TLE,对偶图构图很蛋疼。
对于点数边数很大的求最小割来说,可以构造它的对偶图,构造对偶图要求原图中s和d必须在图的外侧,对偶图G*中的每个点对应G中一个面,每一条从st到sd的最短路径都对应原图s到d的一个最小割。
构造对偶图条件:
1、原图是一个平面图
2、图中的一个点为源点s,另外一个点为汇点t,且s和t都在图中的无界面的边界上
G*中的每个点对应G中一个面
参考文献:周冬《两极相通——浅析最大—最小定理在信息学竞赛中的应用》.
View Code
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 7 const int mn=422222; 8 const int mm=2111111; 9 const int oo=0x3fffffff; 10 int que[mn], inque[mn], dis[mn]; 11 int head[mn], reach[mm], flow[mm], next[mm]; 12 int st, sd, edge; 13 int val[444][444]; 14 15 void addedge(int u, int v, int c1, int c2) 16 { 17 reach[edge]=v, flow[edge]=c1, next[edge]=head[u], head[u]=edge++; 18 reach[edge]=u, flow[edge]=c2, next[edge]=head[v], head[v]=edge++; 19 } 20 21 void spfa() 22 { 23 for(int i=1; i<=sd+5; i++) inque[i]=0, dis[i]=oo; 24 int h=0, t=0; 25 dis[st]=0; 26 que[t++]=st; 27 inque[st]=1; 28 while(h!=t) 29 { 30 int u=que[h++]; 31 if(h==mn) h=0; ///!循环队列 32 inque[u]=0; 33 for(int i=head[u]; i>=0; i=next[i]) 34 { 35 int v=reach[i], val=flow[i]; 36 if(dis[v]>dis[u]+val) ///当满足这个条件时才进行下面的操作 37 { 38 dis[v]=dis[u]+val; ///松弛操作 39 if(!inque[v]) 40 { 41 inque[v]=1; 42 que[t++]=v; 43 if(t==mn) t=0; ///循环队列 44 } 45 } 46 } 47 } 48 } 49 50 int main() 51 { 52 int n, m, T; 53 cin >> T; 54 while(T--) 55 { 56 scanf("%d",&n); 57 st=0, sd=n*n+1; 58 memset(head,-1,sizeof(head)); 59 for(int i=1; i<=n; i++) 60 for(int j=1; j<=n; j++) scanf("%d",&val[i][j]); 61 for(int i=1; i<n; i++) 62 { 63 addedge(st,i,val[1][i],val[1][i]); 64 addedge(st,(i-1)*(n-1)+(n-1),val[i][n],val[i][n]); 65 addedge((i-1)*(n-1)+1,sd,val[i][1],val[i][1]); 66 addedge((n-2)*(n-1)+i,sd,val[n][i],val[n][i]); 67 } 68 for(int i=1; i<=n-1; i++) 69 for(int j=1; j<=n-1; j++) 70 { 71 if(j+1<=n-1)addedge((i-1)*(n-1)+j,(i-1)*(n-1)+j+1,val[i][j+1],val[i][j+1]); 72 if(i+1<=n-1)addedge((i-1)*(n-1)+j,i*(n-1)+j,val[i+1][j],val[i+1][j]); 73 } 74 spfa(); 75 printf("%d\n",dis[sd]); 76 } 77 return 0; 78 }