P1345奶牛的电信(最小割)
题目描述
农夫约翰的奶牛们喜欢通过电邮保持联系,于是她们建立了一个奶牛电脑网络,以便互相交流。这些机器用如下的方式发送电邮:如果存在一个由 cc 台电脑组成的序列a_1,a_2,\cdots ,a_ca1,a2,⋯,ac,且 a_1a1 与 a_2a2 相连,a_2a2 与 a_3a3 相连,等等。那么电脑 a_1a1 和 a_cac 就可以互发电邮。
很不幸,有时候奶牛会不小心踩到电脑上,农夫约翰的车也可能碾过电脑,这台倒霉的电脑就会坏掉。这意味着这台电脑不能再发送电邮了,于是与这台电脑相关的连接也就不可用了。
有两头奶牛就想:如果我们两个不能互发电邮,至少需要坏掉多少台电脑呢?请编写一个程序为她们计算这个最小值。
以如下网络为例:
1*
/
3 - 2*
这张图画的是有 22 条连接的 33 台电脑。我们想要在电脑 11 和 22 之间传送信息。电脑 11 与 33,22 与 33 直接连通。如果电脑 33 坏了,电脑 11 与 22 便不能互发信息了。
输入格式
第一行:四个由空格分隔的整数:N,M,c_1,c_2N,M,c1,c2。NN 是电脑总数,电脑由 11 到 NN 编号。MM 是电脑之间连接的总数。后面的两个整数 c_1c1 和 c_2c2 是上述两头奶牛使用的电脑编号。连接没有重复且均为双向的(即如果 c_1c1 与 c_2c2 相连,那么 c_2c2 与 c_1c1 也相连)。两台电脑之间至多有一条连接。电脑 c_1c1 和 c_2c2 不会直接相连。
第 22 到 M+1M+1 行:接下来的 MM 行中,每行包含两台直接相连的电脑的编号。
输出格式
一行,一个整数,表示使电脑 c_1c1 和 c_2c2 不能互相通信需要坏掉的电脑数目的最小值。
题解:
就是给出一个无向图,询问最少删掉几个点,使得c1和c2不连通。
把每个点拆成两个点,简称上点和下点。对于每条边,x的上点向y的下点连一条单向边,反之亦然。
最后把c1的上点作为源点,c2的下点作为汇点跑Dinic算法即可。
#include<bits/stdc++.h> using namespace std; const int maxn=1e6+10; const int inf=1e9; int n,m; struct node { int u,v,w,nxt; }edge[maxn]; int head[maxn]; int tot; void addedge (int u,int v,int w) { edge[tot].u=u; edge[tot].v=v; edge[tot].w=w; edge[tot].nxt=head[u]; head[u]=tot++; } int dep[maxn]; int inq[maxn]; int cur[maxn]; int wjm; int maxflow=0; int s,t; bool bfs () { for (int i=1;i<=2*n;i++) { cur[i]=head[i]; dep[i]=inf; inq[i]=0; } dep[s]=0; queue<int> q; q.push(s); while (!q.empty()) { int u=q.front(); q.pop(); inq[u]=0; for (int i=head[u];i!=-1;i=edge[i].nxt) { int v=edge[i].v; if (dep[v]>dep[u]+1&&edge[i].w) { dep[v]=dep[u]+1; if (inq[v]==0) { q.push(v); inq[v]=1; } } } } if (dep[t]!=inf) return 1; return 0; } int dfs (int u,int flow) { int increase=0; if (u==t) { wjm=1; maxflow+=flow; return flow; } int used=0; for (int i=cur[u];i!=-1;i=edge[i].nxt) { cur[u]=i; int v=edge[i].v; if (edge[i].w&&dep[v]==dep[u]+1) { if (increase=dfs(v,min(flow-used,edge[i].w))) { used+=increase; edge[i].w-=increase; edge[i^1].w+=increase; if (used==flow) break; } } } return used; } int Dinic () { while (bfs()) { wjm=1; while (wjm==1) { wjm=0; dfs(s,inf); } } return maxflow; } int main () { scanf("%d%d%d%d",&n,&m,&s,&t); memset(head,-1,sizeof(head)); //s=0,t=n+1; s+=n; for (int i=1;i<=n;i++) { addedge(i,i+n,1); addedge(i+n,i,0); } for (int i=1;i<=m;i++) { int x,y; scanf("%d%d",&x,&y); addedge(y+n,x,inf); addedge(x,y+n,0); addedge(x+n,y,inf); addedge(y,x+n,0); } printf("%d\n",Dinic()); }