p1342奶牛通讯
描述 Description
农夫约翰的奶牛们喜欢通过电邮保持联系,于是她们建立了一个奶牛电脑网络,以便互相交流。这些机器用如下的方式发送电邮:如果存在一个由c台电脑组成的序列a1,a2,...,a(c),且a1与a2相连,a2与a3相连,等等,那么电脑a1和a(c)就可以互发电邮。
很不幸,有时候奶牛会不小心踩到电脑上,农夫约翰的车也可能碾过电脑,这台倒霉的电脑就会坏掉。这意味着这台电脑不能再发送电邮了,于是与这台电脑相关的连接也就不可用了。
有两头奶牛就想:如果我们两个不能互发电邮,至少需要坏掉多少台电脑呢?请编写一个程序为她们计算这个最小值和与之对应的坏掉的电脑集合。
以如下网络为例:
1*
/
3 - 2*
这张图画的是有2条连接的3台电脑。我们想要在电脑1和2之间传送信息。电脑1与3、2与3直接连通。如果电脑3坏了,电脑1与2便不能互发信息了。
输入格式 Input Format
第一行四个由空格分隔的整数:N,M,c1,c2.N是电脑总数(1<=N<=100),电脑由1到N编号。M是电脑之间连接的总数(1<= M<=600)。最后的两个整数c1和c2是上述两头奶牛使用的电脑编号。连接没有重复且均为双向的(即如果c1与c2相连,那么c2与c1也相连)。两台电脑之间至多有一条连接。电脑c1和c2不会直接相连。 第2到M+1行 接下来的M行中,每行包含两台直接相连的电脑的编号。
输出格式 Output Format
输出共有两行。第一行是使电脑c1和c2不能互相通信需要坏掉的电脑数目的最小值。第二行是排好序的坏掉的电脑的编号列表。注意c1和c2都不能坏掉。如果有多种可能情况,输出第一个数最小的一种,如果第一个数相同,则输出第二个数最小的一种,依此类推。
样例输入 Sample Input
3 2 1 2
1 3
2 3
样例输出 Sample Output
1
3
时间限制 Time Limitation
1s
注释 Hint
1s
来源 Source
usaco 5.4.5
思路:这道题就是一个裸的最小割,先把图建好然后跑一边最大流就是最小割然后在将某个点删除看看最小割是不是减小,如果减小
则记录下这个点,这个点就是从start到end需要踩坏的电脑(奶牛也是真的有钱哇)然后输出即可。
代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define INF 0x7fffffff using namespace std; struct edge { int y,next,v; }a[31000],c[31000]; int lin[31000]; int rev[31000]; int l[1000]; int len=0; int q[31000]; int n,m,s,e; bool f[1000]; int ans1[1000]; void insert(int x,int y,int v) { a[++len].y=y; a[len].v=v; a[len].next=lin[x]; lin[x]=len; rev[len]=len+1; a[++len].y=x; a[len].v=0; a[len].next=lin[y]; lin[y]=len; rev[len]=len-1; } bool make_level() { int head=0,tail=1; memset(l,-1,sizeof(l)); q[1]=s; l[s]=1; while(head++<tail) { int tn=q[head]; for(int i=lin[tn];i;i=a[i].next) { if(a[i].v&&l[a[i].y]<0&&!f[a[i].y]) { q[++tail]=a[i].y; l[q[tail]]=l[tn]+1; } } } return l[e]>=0; } int MAX(int k,int flow) { if(k==e)//到结束的点刚开始手残打个n....... return flow; int maxflow=0,d=0; for(int i=lin[k];i&&maxflow<flow;i=a[i].next) { if(l[a[i].y]==l[k]+1&&a[i].v&&!f[a[i].y]) { if(d=MAX(a[i].y,min(flow-maxflow,a[i].v))) { maxflow+=d; a[i].v-=d; a[rev[i]].v+=d; } } } if(!maxflow) l[k]=-1; return maxflow; } int sum=0; bool check=true; void Dinic() { int d=0; while(make_level()) while(d=MAX(s,INF)) sum+=d; } int main() { memset(f,false,sizeof(f)); cin>>n>>m>>s>>e; for(int i=1;i<=m;i++) { int x,y; cin>>x>>y; if(x==s)//如果x就是起点,拆点 { insert(s,y,INF); insert(y+n,s,INF); } else if(y==s)//如果y是起点 { insert(s,x,INF); insert(x+n,s,INF); } else if(x==e)//如果x为终点 { insert(e,y,INF); insert(y+n,e,INF); } else if(y==e)//如果y为终点 { insert(e,x,INF); insert(x+n,e,INF); } else { insert(y+n,x,INF); insert(x+n,y,INF); } } for(int i=1;i<=n;i++)//如果不是起点和终点就将每个点拆成i和i' if(i!=s&&i!=e) insert(i,i+n,1); memcpy(c,a,sizeof(c)); Dinic(); cout<<sum<<endl; int ans=sum; for(int i=1;i<=n;i++) { if(i==s||i==e) continue; memcpy(a,c,sizeof(a)); sum=0; f[i]=1; Dinic(); if(sum<ans) ans1[++ans1[0]]=i,ans=sum; else f[i]=0; } for(int i=1;i<=ans1[0];i++) cout<<ans1[i]<<' '; return 0; }