zoukankan      html  css  js  c++  java
  • 洛谷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 }
  • 相关阅读:
    JAVA学习日记1-0706
    同步一个fork
    面试题 17.13. 恢复空格-7月9日
    3. 无重复字符的最长子串(leetcode)-7月8日
    面试题 16.11. 跳水板(leetcode)-7月8日
    112.路径总和(leetcode)-7月7日
    Git使用入门
    第一次尝试
    OpenPCDet: Open-MMLab 面向LiDAR点云表征的3D目标检测代码库
    人工智能和机器学习能为抗击新冠肺炎做些什么?
  • 原文地址:https://www.cnblogs.com/five20/p/8138219.html
Copyright © 2011-2022 走看看