读完题就知道是求两点独立轨条数的问题。
就是将一个点拆成两个点求最大流。
但是在如何将一个点拆分成两个点之后如何建图的问题上纠结了好久。
其实就是将一个点拆分成流入点和流出点。然后流入到流出之间有一条容量为1的有向弧。
原来的a和b之间联通的话,就是a的出点流到了b的入点,且b的出点流到了a的入点。
还有一个问题要解决,就是有多个最小割时如何得到集合大小最小,且字典序最小的集合。
其实因为拆分之后的流入点到流出点之间的容量为1,且原来每个点拆分之后的自己的流入和流出之间的容量都为1.
可以证明所有的最小割的集合大小相等。所以只要找到字典序最小的那个就好了。
根据退流定理,枚举删除每个点。
先找到编号最小的一个割点。
然后删除这个点,求得删除这个点之后的最大流。将容量网络恢复。并在容量网络中删除这个点。一直重复这一步直到容量网络的最大流变为0.
/*
ID: modengd1
PROG: telecow
LANG: C++
*/
#include <iostream>
#include <stdio.h>
#include <memory.h>
#include <queue>
#include <vector>
using namespace std;
#define Max_int 0x7fff
bool available[101];
vector<int> ans;
bool vis[101][2];
int ans1;
int level[101][2];
int newG[101][2][101][2];
int newGC[101][2][101][2];
int N,M,A,B;
void BFS(int s,int side)
{
memset(level,-1,sizeof(level));
level[s][side]=0;
queue<pair<int,int> > Q;
Q.push(pair<int,int>(s,side));
while(!Q.empty())
{
pair<int,int> P=Q.front();Q.pop();
for(int i=1;i<=N;i++)
{
if(available[i])
for(int j=0;j<2;j++)
{
if(newG[P.first][P.second][i][j]&&level[i][j]<0)
{
level[i][j]=level[P.first][P.second]+1;
Q.push(pair<int,int>(i,j));
}
}
}
}
}
int DFS(int s,int side,int t,int f)
{
if(s==t)
return f;
for(int i=1;i<=N;i++)
{
if(available[i])
for(int j=0;j<2;j++)
{
if(newG[s][side][i][j]&&level[s][side]+1==level[i][j])
{
int d=DFS(i,j,t,min(f,newG[s][side][i][j]));
if(d>0)
{
newG[s][side][i][j]-=d;
newG[i][j][s][side]+=d;
return d;
}
}
}
}
return 0;
}
int max_flow(int s,int t)
{
int flow=0;
while(true)
{
BFS(s,1);
if(level[t][0]<0)
return flow;
int f;
while((f=DFS(s,1,t,Max_int))>0)
flow+=f;
}
return flow;
}
void slove()
{
memcpy(newGC,newG,sizeof(newGC));
memset(available,true,sizeof(available));
ans1=max_flow(A,B);
cout<<ans1<<endl;
memcpy(newG,newGC,sizeof(newG));
for(int i=1;i<=N;i++)
{
if(i==A||i==B)
continue;
available[i]=false;
int f;
memcpy(newG,newGC,sizeof(newGC));//恢复容量网络
if(ans1>(f=max_flow(A,B)))
{
ans.push_back(i);
ans1=f;//删除这个点之后容量网络的最大流
}
else
available[i]=true;
}
cout<<ans[0];
for(int i=1;i<ans.size();i++)
cout<<‘ ‘<<ans[i];
cout<<endl;
}
int main()
{
freopen("telecow.in","r",stdin);
freopen("telecow.out","w",stdout);
scanf("%d%d%d%d",&N,&M,&A,&B);
for(int i=0;i<M;i++)//输入原图
{
int a,b;
scanf("%d%d",&a,&b);
newG[a][1][b][0]=Max_int;
newG[b][1][a][0]=Max_int;
}
for(int i=1;i<=N;i++)//每个点拆分出来的两个点之间流量为1
{
newG[i][0][i][1]=1;
}
slove();
return 0;
}
原文:http://www.cnblogs.com/modengdubai/p/4865569.html