转自:http://blog.youkuaiyun.com/scorpiocj/article/details/6070518
题目模型就是从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));
- queue<<span class="datatypes" style="margin: 0px; padding: 0px; border: none; color: rgb(46, 139, 87); background-color: inherit; font-weight: bold;">int>q;
- 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]
- {
- dis[u]=dis[v];
- cur[u]=v;
- }
- }
- dis[u]++;
- num[dis[u]]++;
- if(u!=s)
- u=pre[u];
- }
- return flow;
- }
- int main()
- {
- int i,j,x,flag=0,cur_flow;
- scanf("%d%d%d",&n,&s,&t);
- s=s+n;//新源点
- for(i=1;i<=n;i++)
- {
- c[i][i+n]=1;
- }
- for(i=1;i<=n;i++)
- {
- for(j=1;j<=n;j++)
- {
- scanf("%d",&x);
- if(x)
- {
- if(i==s-n&&j==t)
- flag=1;
- c[i+n][j]=inf;
- }
- }
- }
- if(flag)
- {
- printf("NO ANSWER!/n");
- return 0;
- }
- cnt=0;
- max_flow=sap();
- for(i=1;i<=n;i++)
- {
- if(i==s-n||i==t)
- continue;
- c[i][i+n]=0;
- memset(f,0,sizeof(f));//不要忘记这一步!!!
- cur_flow=sap();
- if(cur_flow
- {
- cnt++;
- ans[cnt]=i;
- max_flow--;
- }
- else
- {
- c[i][i+n]=1;
- }
- if(max_flow<=0)
- break;
- }
- cout<<cnt<<endl;
- for(i=1;i<=cnt;i++)
- {
- if(i!=cnt)
- printf("%d ",ans[i]);
- else
- printf("%d",ans[i]);
- }
- printf("/n");
- return 0;
- }