【题目描述】
农夫约翰的奶牛们喜欢通过电邮保持联系,于是她们建立了一个奶牛电脑网络,以便互相交流。这些机器用如下的方式发送电邮:如果存在一个由c台电脑组成的序列a1,a2,...,a(c),且a1与a2相连,a2与a3相连,等等,那么电脑a1和a(c)就可以互发电邮。很不幸,有时候奶牛会不小心踩到电脑上,农夫约翰的车也可能碾过电脑,这台倒霉的电脑就会坏掉。这意味着这台电脑不能再发送电邮了,于是与这台电脑相关的连接也就不可用了。有两头奶牛就想:如果我们两个不能互发电邮,至少需要坏掉多少台电脑呢?请编写一个程序为她们计算这个最小值和与之对应的坏掉的电脑集合。
【吐槽】
首先,很容易想到拆点,然后建图就很容易了。
建好图后,就是计算一个最小割,跑最大流即可。
但这道题丧心病狂,让求删去的点集,于是我们考虑一个点,如果删去这个点,最小割变小了,那么这个点就是所求点。
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<ctime> #include<algorithm> using namespace std; #define INF 1000000000 #define MAXN 6000 struct node{int y,next,v,rel;}e[MAXN*4],E[MAXN*4]; int n,m,S,T,len,ans,Link[MAXN],level[MAXN],q[MAXN],ans2[MAXN],f[MAXN]; inline int read() { int x=0,f=1; char ch=getchar(); while(!isdigit(ch)) {if(ch=='-') f=-1; ch=getchar();} while(isdigit(ch)) {x=x*10+ch-'0'; ch=getchar();} return x*f; } void insert(int x,int y,int v) { e[++len].next=Link[x];Link[x]=len;e[len].y=y;e[len].v=v;e[len].rel=len+1; e[++len].next=Link[y];Link[y]=len;e[len].y=x;e[len].v=0;e[len].rel=len-1; } void build() { n=read(),m=read(),S=read(),T=read(); for(int i=1;i<=m;i++) { int x=read(),y=read(); if(x==S) {insert(S,y,INF); insert(y+n,S,INF);} else if(y==S) {insert(S,x,INF); insert(x+n,S,INF);} else if(x==T) {insert(T,y,INF); insert(y+n,T,INF);} else if(y==T) {insert(T,x,INF); insert(x+n,T,INF);} else {insert(y+n,x,INF); insert(x+n,y,INF);} } for(int i=1;i<=n;i++) if(i!=S&&i!=T) insert(i,i+n,1); } bool bfs() { memset(level,-1,sizeof(level)); level[S]=1; q[1]=S; int head=0,tail=1; while(++head<=tail) { for(int i=Link[q[head]];i;i=e[i].next) if(e[i].v&&level[e[i].y]<0&&!f[e[i].y]) { q[++tail]=e[i].y; level[q[tail]]=level[q[head]]+1; } } return level[T]>=0; } int MAXFLOW(int x,int flow) { if(x==T) return flow; int maxflow=0,d=0; for(int i=Link[x];i&&maxflow<flow;i=e[i].next) if(level[e[i].y]==level[x]+1&&e[i].v&&!f[e[i].y]) if(d=MAXFLOW(e[i].y,min(e[i].v,flow-maxflow))) { maxflow+=d; e[i].v-=d; e[e[i].rel].v+=d; } if(!maxflow) level[x]=-1; return maxflow; } void solve() { int d=0;ans=0; while(bfs()) while(d=MAXFLOW(S,INF)) ans+=d; } void work() { int sum=ans; for(int i=1;i<=n;i++) { if(i==S||i==T)continue; memcpy(e,E,sizeof(e)); f[i]=1; solve(); if(ans<sum) ans2[++ans2[0]]=i,sum=ans; else f[i]=0; } for(int i=1;i<=ans2[0];i++) printf("%d ",ans2[i]); } int main() { //freopen("cin.in","r",stdin); //freopen("cout.out","w",stdout); build(); memcpy(E,e,sizeof(e)); solve(); printf("%d ",ans); work(); return 0; }