正题
第五题:[USACO5.4]奶牛的电信Telecowmunication
这道题做多网络流的人一看就知道是一道最小割点的题目。
做多强联通的人一看就知道是一道割点(割顶)的题目。
如果让我们用网络流来做,我们会怎样构图呢?
根据题目的性质我们可以知道,每个点只能被割一次。所以我们怎么限制这个条件呢?明显就是把一个点拆成两个点,然后在其中直连一条流量为1的边。其他的原图有的边直接连即可(无向当然要建)。最后从保证c1和c2不能被割,于是把c1的出点作为源点,把c2的入点作为汇点,跑一遍最大流来求出最小割点集即可。
代码<强联通不会>
#include
#include
#include
#include
#define INF 1e9
using namespace std;
int n,m,c1,c2;
int begin,end;
struct edge{
int y,next,c;
}s[100010];
int first[210];
int len=1;
queue f;
int h[110];
void ins(int x,int y,int c){
len++;s[len].y=y;s[len].c=c;s[len].next=first[x];first[x]=len;
len++;s[len].y=x;s[len].c=0;s[len].next=first[y];first[y]=len;
}
bool bfs(){
f.push(begin);
for(int i=1;i<=2*n;i++)
h[i]=INF;
h[begin]=0;
while(!f.empty()){
int x=f.front();
f.pop();
for(int i=first[x];i!=0;i=s[i].next){
int y=s[i].y;
if(h[y]==1e9 && s[i].c>0){
h[y]=h[x]+1;
f.push(y);
}
}
}
return h[end]!=1e9;
}
int dfs(int x,int t){
if(x==end) return t;
int tot=0;
for(int i=first[x];i!=0;i=s[i].next){
int y=s[i].y;
if(t==tot) return t;
if(h[y]==h[x]+1 && s[i].c>0){
int my=dfs(y,min(s[i].c,t-tot));
tot+=my;s[i].c-=my;s[i^1].c+=my;
}
}
if(tot==0) h[x]=0;
return tot;
}
int max_flow(){
int tot=0;
while(bfs()){
int dx=dfs(begin,1e9);
while(dx!=0){
tot+=dx;
dx=dfs(begin,1e9);
}
}
return tot;
}
int main(){
scanf("%d %d %d %d",&n,&m,&c1,&c2);
for(int i=1;i<=m;i++){
int x,y;
scanf("%d %d",&x,&y);
ins(x+n,y,INF);
ins(y+n,x,INF);
}
begin=0;end=2*n+1;
for(int i=1;i<=n;i++)
ins(i,i+n,1);
begin=c1+n;
end=c2;
printf("%d",max_flow());
}