挺无聊的一道网络流
不过有一个挺有特色的地方是要枚举汇点,觉得挺好玩的就记录下来吧
题意:有N个点,每两个点间都有一条双向边,问使这些点中至少有两个点不连通所需要破坏的边的最小权值
题目链接:http://cstest.scu.edu.cn/soj/problem.action?id=3134
取任意点为S点,若u,v两点不连通,则u,v中至少有一个与S也不连通。
因为题目中均为双向边,若u,v均与s连通,那么由路径u->s->v可知u,v也应该是连通的
所以显然S点是可以任取的,但是T点是需要枚举的。
那么就枚举T点依次求最小割,取最小值
PS:这道题写的比较早,那时候我的sap模板还很挫。。还加了dinic优化的。。后来发现稠密图用dinic实在是慢,参考了lieyan大神的代码后就去掉了bfs预处理。。
#include<cstdio> #include<cstring> #include<queue> #define INF 0x7f7f7f7f using namespace std; int p[105],d[105],gap[105],cap[105][105],f[105][105],S,T; void bfs(int n) { int u,v; memset(d,-1,sizeof(d)); memset(gap,0,sizeof(gap)); queue<int>dd; dd.push(T); d[T]=0;gap[0]=1; while(!dd.empty()) { u=dd.front();dd.pop(); for(v=1;v<=n;v++) if((cap[v][u]>f[v][u])&&(d[v]==-1)) { d[v]=d[u]+1; gap[d[v]]++; dd.push(v); } } } int sap(int n) { int v,u,a,mind,ans; bfs(n); u=S;ans=0; memset(p,-1,sizeof(p)); while(d[S]<n) { for(v=1;v<=n;v++)if(cap[u][v]>f[u][v]&&d[u]==d[v]+1 ) break; if(v<=n) { p[v]=u;u=v; if(v==T) { int a=INF; for(v=T;v!=S;v=p[v])a=a<(cap[p[v]][v]-f[p[v]][v])?a:(cap[p[v]][v]-f[p[v]][v]); for(v=T;v!=S;v=p[v]) { f[p[v]][v]+=a; f[v][p[v]]-=a; } ans+=a; u=S; } } else { int mind=n; for(v=1;v<=n;v++)if(cap[u][v]>f[u][v])mind=mind<d[v]+1?mind:d[v]+1; --gap[d[u]]; if(gap[d[u]]==0)return ans; ++gap[mind]; d[u]= mind; if(u!=S) u=p[u]; } } return ans; } int main() { int n,i,j,ans,x; while(scanf("%d",&n)!=EOF) { for(i=1;i<=n;i++) for(j=1;j<=n;j++) scanf("%d",&cap[i][j]); ans=INF; S=1; for(T=2;T<=n;T++) { memset(f,0,sizeof(f)); x=sap(n); ans=ans<x?ans:x; } printf("%d\n",ans); } }