POJ 2914 无向图最小割
以前总结过无向图最小割的最大流算法,n^2的枚举起点和终点,这个题必然tle
于是又学习了专门的算法:Stoer-Wagner算法
就是利用prim求最大生成树,将最后扫到的两点合并,执行n-1次,最终合并成一个点
参考资料:
View Code
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <algorithm> 5 #include <iostream> 6 7 #define N 600 8 #define INF 1e9 9 10 using namespace std; 11 12 int map[N][N],q[N],dis[N]; 13 bool vis[N],cut[N]; 14 int n,m,S,T; 15 16 inline void read() 17 { 18 memset(map,0,sizeof map); 19 memset(cut,0,sizeof cut); 20 for(int i=1,a,b,c;i<=m;i++) 21 { 22 scanf("%d%d%d",&a,&b,&c); 23 map[a][b]+=c; map[b][a]+=c; 24 } 25 } 26 //Stoer-Wagner算法 27 //prim求出最大生成树,将最后扫到的两点合并,执行n-1次 28 inline int mincut(int now) 29 { 30 int tot=0; 31 memset(vis,0,sizeof vis); 32 memset(dis,0,sizeof dis); 33 for(int j=0,tmp,k;j<now;j++) 34 { 35 tmp=-INF; 36 for(int i=0;i<n;i++) 37 if(!cut[i]&&!vis[i]&&tmp<dis[i]) tmp=dis[i],k=i; 38 q[++tot]=k; vis[k]=true; 39 for(int i=0;i<n;i++) 40 if(!cut[i]&&!vis[i]) dis[i]+=map[k][i]; 41 } 42 S=q[tot-1]; T=q[tot]; 43 return dis[T]; 44 } 45 46 inline void contract() 47 { 48 map[S][T]=map[T][S]=0; 49 cut[T]=true; 50 for(int i=0;i<n;i++) 51 if(i!=S&&!cut[i]) map[i][S]=map[S][i]=map[S][i]+map[T][i]; 52 } 53 54 inline void go() 55 { 56 int ans=INF; 57 for(int i=n;i>1;i--) 58 { 59 ans=min(ans,mincut(i)); 60 contract(); 61 } 62 printf("%d\n",ans); 63 } 64 65 int main() 66 { 67 while(scanf("%d%d",&n,&m)!=EOF) read(),go(); 68 return 0; 69 }
没有人能阻止我前进的步伐,除了我自己!