POJ 1815 Friendship

题目模型就是从s到t的连通图中,最少删除多少个点,可以使s和t不连通,也就是求一个最小点割集(最小点割集的概念见下面的链接)

 

http://hi.baidu.com/492943457/blog/item/1401d1a964a3cdbfcb130c89.html

 

将s看成源点,t看成汇点,有结论:源点到汇点的最小点割集的大小等于图中最多的点不相交路径数目

 

做法:将每个点拆成两个点u和u',之间连容量为1的边,原来从u到v的边,变成从u'到v的边,边容量都是无穷大,新源点为s',新汇点还是t

 

这样,就将点不相交问题转化成边不相交问题,每条点不相交路径和一条边不相交路径一一对应

 

当有流值v时,意味着有v条边不相交路径(容量为1的限制),任意割的容量p>=v,每条边不相交路径中必有一条边是割边,当割是最小割

 

时,p=v,v为最大流,这时,最小点割集的大小就是最小边割集的大小也就是最大流

 

于是,当源点和汇点不直接相连的情况下,我们就得到了我们的第一个答案

 

但是题目要求很高,需要输出分数最小的点割集,即按字典序排序最小,我们可以贪心地从最小标号的顶点到最大标号的顶点一次枚举,每次删

 

除边i和i',如果新的最大流比原来的最大流小,说明该点在最小点割集中,否则,恢复边i和i'(不然可能将原来不是割点的点变成割点)

 

代码:

#include #include #include using namespace std; const int inf=1<<30; const int MAX=405; int c[MAX][MAX],f[MAX][MAX],rc[MAX],pre[MAX],q[MAX]; int dis[MAX],num[MAX],tmp1[MAX],tmp2[MAX],ans[MAX],cur[MAX]; int s,t,n,max_flow,cnt; void bfs() { int u,v,i,vis[MAX]; memset(dis,0,sizeof(dis)); memset(num,0,sizeof(num)); queueq; q.push(t); vis[t]=0; dis[t]=0; num[0]++; while(!q.empty()) { u=q.front(); q.pop(); for(v=1;v<=2*n;v++) { if(c[v][u]&&!vis[u]) { dis[v]=dis[v]+1; num[dis[v]]++; vis[v]=1; q.push(v); } } } } int sap() { int u,v,i,aug=inf,flag,flow=0; for(i=1;i<=2*n;i++) { dis[i]=num[i]=0; cur[i]=1; } bfs(); u=s; num[0]=2*n; while(dis[s]<2*n) { flag=0; for(v=cur[u];v<=2*n;v++) { if(c[u][v]>f[u][v]&&dis[u]==dis[v]+1) { flag=1; pre[v]=u; cur[u]=v; aug=min(aug,c[u][v]-f[u][v]); u=v; if(u==t) { flow+=aug; while(u!=s) { f[pre[u]][u]+=aug; f[u][pre[u]]-=aug; u=pre[u]; } aug=inf; u=s; } break; } } if(flag) continue; if(--num[dis[u]]==0) return flow; dis[u]=inf; for(v=1;v<=2*n;v++) { if(c[u][v]>f[u][v]&&dis[v]

 

 

你可能感兴趣的:(POJ,网络流)