zoukankan      html  css  js  c++  java
  • bzoj3504: [Cqoi2014]危桥

    Description

    Alice和Bob居住在一个由N座岛屿组成的国家,岛屿被编号为0到N-1。某些岛屿之间有桥相连,桥上的道路是双
    向的,但一次只能供一人通行。其中一些桥由于年久失修成为危桥,最多只能通行两次。Alice希望在岛屿al和a2之间往返an次(从al到a2再从a2到al算一次往返)。同时,Bob希望在岛屿bl和b2之间往返bn次。这个过程中,所有危桥最多通行两次,其余的桥可以无限次通行。请问Alice和Bob能完成他们的愿望吗?

    Input


    本题有多组测试数据。
    每组数据第一行包含7个空格隔开的整数,分别为N、al、a2、an、bl、b2、bn。
    接下来是一个N行N列的对称矩阵,由大写字母组成。矩阵的i行j列描述编号i一1和j-l的岛屿间的连接情况,若为“O”则表示有危桥相连:为“N”表示有普通的桥相连:为“X”表示没有桥相连。
    |

    Output

    对于每组测试数据输出一行,如果他们都能完成愿望输出“Yes”,否则输出“No”。

    Sample Input

    4 0 1 1 2 3 1
    XOXX
    OXOX
    XOXO
    XXOX
    4 0 2 1 1 3 2
    XNXO
    NXOX
    XOXO
    OXOX

    Sample Output

    Yes
    No
    数据范围
    4<=N<50
    O<=a1, a2, b1, b2<=N-1
    1 <=an. b<=50
     
    题解:
    这道题有个看上去正确的方法,就是将原图的边保留,容量为它原来能走的次数,从S向a1,b1分别连容量为an*2,bn*2的边,从a2,b2分别向T连容量为an*2,bn*2的边,然后如果最大流=an*2+bn*2,则可行
    这个方法是错误的
    如图,a1有流向b2的边,b1有流向a2的边,如果这个图满足上面的条件,但它不一定可行
    如何能保证可行?我们只需要将b1和b2交换一下再判一遍即可
    假如一个a1到b2的一个流和b1到a2的一个流分别经过了一个桥的两个端点(u,v),如图
    我们就可以将a1到b2的流量改为经过u-v-a2-T到达T,同理将b1到a2的流量改为经过v-u-b2-T到达T,这样就说明这个流是没有问题的
    在这种情况下将b1和b2交换后,流量显然不会有变化
    如果一个a1到b2的一个流和b1到a2的一个流没有经过任何一个桥的两个端点,这个流显然不合法,且在b1和b2交换后,流量会减小
    所以判两次就行了
    code:
     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cmath>
     4 #include<cstring>
     5 #include<algorithm>
     6 #define maxn 55
     7 #define maxm 5050
     8 #define inf 1061109567
     9 using namespace std;
    10 char s[52];
    11 int n,a1,a2,an,b1,b2,bn;
    12 struct flow{
    13     int s,t,tot,now[maxn],son[maxm],pre[maxm],val[maxm];
    14     int dis[maxn],head,tail,list[maxn];
    15     bool bo[maxn];
    16     void init(){s=0,t=n+1,tot=1,memset(now,0,sizeof(now));}
    17     void put(int a,int b,int c){pre[++tot]=now[a],now[a]=tot,son[tot]=b,val[tot]=c;}
    18     void add(int a,int b,int c){put(a,b,c),put(b,a,0);}
    19     bool bfs(){
    20         memset(bo,0,sizeof(bo));
    21         head=0,tail=1,list[1]=s,dis[s]=0,bo[s]=1;
    22         while (head<tail){
    23             int u=list[++head];
    24             for (int p=now[u],v=son[p];p;p=pre[p],v=son[p])
    25                 if (val[p]&&!bo[v]) bo[v]=1,dis[v]=dis[u]+1,list[++tail]=v;
    26         }
    27         return bo[t];
    28     }
    29     int dfs(int u,int rest){
    30         if (u==t) return rest;
    31         int ans=0;
    32         for (int p=now[u],v=son[p];p&&rest;p=pre[p],v=son[p])
    33             if (val[p]&&dis[v]==dis[u]+1){
    34                 int d=dfs(v,min(rest,val[p]));
    35                 val[p]-=d,val[p^1]+=d,ans+=d,rest-=d;
    36             }
    37         if (!ans) dis[u]=-1;
    38         return ans;
    39     }
    40     int dinic(){
    41         int ans=0;
    42         while (bfs()) ans+=dfs(s,inf);
    43         return ans;
    44     }
    45 }f,g;
    46 int main(){
    47     while (~scanf("%d%d%d%d%d%d%d",&n,&a1,&a2,&an,&b1,&b2,&bn)){
    48         a1++,a2++,an<<=1,b1++,b2++,bn<<=1,f.init();
    49         for (int i=1;i<=n;i++){
    50             scanf("%s",s+1);
    51             for (int j=1;j<=n;j++) if (s[j]=='O') f.add(i,j,2); else if (s[j]=='N') f.add(i,j,inf);
    52         }
    53         g=f;
    54         f.add(f.s,a1,an),f.add(a2,f.t,an),f.add(f.s,b1,bn),f.add(b2,f.t,bn);
    55         g.add(g.s,a1,an),g.add(a2,g.t,an),g.add(g.s,b2,bn),g.add(b1,g.t,bn);
    56         if (f.dinic()==an+bn&&g.dinic()==an+bn) puts("Yes"); else puts("No");
    57     }
    58     return 0;
    59 }
  • 相关阅读:
    BZOJ 3997: [TJOI2015]组合数学 [偏序关系 DP]
    [Sdoi2017]新生舞会 [01分数规划 二分图最大权匹配]
    [Sdoi2017]相关分析 [线段树]
    [Sdoi2017]硬币游戏 [高斯消元 KMP]
    [Sdoi2017]序列计数 [矩阵快速幂]
    [Sdoi2017]树点涂色 [lct 线段树]
    [Sdoi2017]数字表格 [莫比乌斯反演]
    BZOJ 3160: 万径人踪灭 [fft manacher]
    Rabbitmq常见测试
    MQ(消息队列)功能介绍
  • 原文地址:https://www.cnblogs.com/chenyushuo/p/5139556.html
Copyright © 2011-2022 走看看