洛谷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不能互相通信需要坏掉的电脑数目的最小值。

输入输出样例

输入样例#1: 
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 }
原文地址:https://www.cnblogs.com/five20/p/8138219.html