洛谷P1345 [USACO5.4]奶牛的电信(最小割)
题目描述
农夫约翰的奶牛们喜欢通过电邮保持联系,于是她们建立了一个奶牛电脑网络,以便互相交流。这些机器用如下的方式发送电邮:如果存在一个由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便不能互发信息了。
输入输出格式
输入格式:
第一行 四个由空格分隔的整数: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行中,每行包含两台直接相连的电脑的编号。
输出格式:
一个整数表示使电脑c1和c2不能互相通信需要坏掉的电脑数目的最小值。
输入输出样例
3 2 1 2
1 3
2 3
输出样例#1:
1
Solution:
乍一看,求最小割,直接套上网络最大流的模板,关键是注意建图。。。
首先最小割指的是割边,而此题求割点,所以原来的点要拆成边,求最小割时原有的边不能删去。
建图的细节:1、图是无向的,所以需要建双向边。2、图中每个点能且仅可以删去1次,所以对于点有流量限制,于是需要拆点建边(注意此边为单向,容量为1)。3、对于题目输入的边,注意双向,然后就是这些边只起到把图连通起来的作用,而题目所求的是割点,所以原有的边不能删去,所以对于容量并没有限制(容量赋为inf)。
关于拆点时的要求:原图双向边,所以拆点建边后不能破坏原图的性质,假设a到b有双向边,则应该这样建图:a->a'->b->b'->a,其中a到a'和b到b'的边权都为1(拆点建的边,删去相当于删掉了这条边拆前的点),a'到b和b'到a的边权都为inf(原图上本来存在的边不能删去,赋值为inf)。
关于我的代码的解释:为了方便,我直接将所有点都拆了并赋边权值为1,但实际上S和T不能拆,所以我将S用S'代替(s+=n),而T不变。
不懂就按照思路画图,很容易理解。
代码:
1 #include<bits/stdc++.h> 2 #define il inline 3 using namespace std; 4 const int N=100005,inf=2333333; 5 int n,m,s,t,ans,h[N],cnt=1,dis[N]; 6 struct edge{ 7 int to,net,v; 8 }e[N*2]; 9 il void add(int u,int v,int w) 10 { 11 e[++cnt].to=v,e[cnt].net=h[u],e[cnt].v=w,h[u]=cnt; 12 e[++cnt].to=u,e[cnt].net=h[v],e[cnt].v=0,h[v]=cnt; 13 } 14 queue<int>q; 15 il bool bfs() 16 { 17 memset(dis,-1,sizeof(dis)); 18 dis[s]=0,q.push(s); 19 while(!q.empty()) 20 { 21 int u=q.front();q.pop(); 22 for(int i=h[u];i;i=e[i].net) 23 if(dis[e[i].to]==-1&&e[i].v>0)dis[e[i].to]=dis[u]+1,q.push(e[i].to); 24 } 25 return dis[t]!=-1; 26 } 27 il int dfs(int u,int op) 28 { 29 if(u==t)return op; 30 int flow=0,used=0; 31 for(int i=h[u];i;i=e[i].net) 32 { 33 int v=e[i].to; 34 if(dis[v]==dis[u]+1&&e[i].v>0) 35 { 36 used=dfs(v,min(op,e[i].v)); 37 if(!used)continue; 38 flow+=used,op-=used; 39 e[i].v-=used,e[i^1].v-=used; 40 } 41 } 42 if(!flow)dis[u]=-1; 43 return flow; 44 } 45 int main() 46 { 47 scanf("%d%d%d%d",&n,&m,&s,&t); 48 int u,v;s+=n; 49 for(int i=1;i<=n;i++)add(i,i+n,1); 50 for(int i=1;i<=m;i++){ 51 scanf("%d%d",&u,&v); 52 add(v+n,u,inf);add(u+n,v,inf); 53 } 54 while(bfs())ans+=dfs(s,inf); 55 cout<<ans; 56 return 0; 57 }