zoukankan      html  css  js  c++  java
  • BZOJ 3504 CQOI 危桥

    3504: [Cqoi2014]危桥

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 1882  Solved: 951
    [Submit][Status][Discuss]

    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

    HINT

     

    Source

    找到了个好的证明

     

    解析:这道题其实第一眼看上去是(和谐)题,然后发现水水的写完后WA了,然后从网上下来数据来观测数据,发现自己WA的地方都是同一个地方,之后上网上看了看其他人的姿势,算是懂了这道题吧。

    首先读完题后,第一眼被这个往返卡了一会,后来发现,假如说从A到B,AB间是危桥的话,那你顶多在其中往返一次,也就是对应流量为1,如此的话,因为无向,所以B到A也必然有流量为1的一条路,在加上点细节修饰以及自己手画个图就能明白。

    接下来我就以为这道题已经完事了,直接写了发最大流一跑发现WA了!

    后经我亲测数据发现有的时候的流量并非自己所希望的从a1流向a2,有的满流的情况居然是从a1流到b2,这样怎么搞?

    然后题解里给出了种办法,就是跑完第一次最大流后如果是满流则重新建图,其中桥的部分不变,源点到a1,a2到汇点的部分不变,只需要把原来的源点到b1,b2到汇点改为源点到b2,b1到汇点即可,再次判断,如果这样跑出来还是满流的话,就有解。

    不过遗憾的是我并没有找到证明,所以就自己写了个证明,不知其严谨性。

    第一次满流后

    假设a1->a2 流量为 an-x

    a1->b2 流量为 x

    b1->a2 流量为 x

    b1->b2 流量为 bn-x

    之后我们假设第二次跑完之后又达到满流。

    则a1->a2 流量仍为 an-x

    ∴a1->b1 流量为 x

    b2->a2 流量为 x

    b2->b1 流量为bn-x

    又先前a1->b2 流量为x

    ∴a1->b2->b1流量为x(无向图)

    则b2->b1又可有流量为x的一条路

    又b2->b1已有流量为bn-x的一条路

    ∴b2->b1有流量为bn的一条路

    则a1->a2有流量为an的一条路

    得证

    于是乎按照这个思路再跑一遍最大流就行了。

    #include <bits/stdc++.h>
    #define ll long long
    #define inf 1e9+10
    using namespace std;
    inline int read(){
    	int x=0;int f=1;char ch=getchar();
    	while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
    	while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
    	return x*f;
    }
    const int MAXN=1e5+10;
    struct node{
    	int y,next,linkk,flow,back;
    }e[MAXN];
    int linkk[MAXN],level[100],q[MAXN],head,tail,len,n,s,t,a1,a2,b1,b2,an,bn,col[60][60];
    inline void insert(int x,int y,int f){
    	e[++len].y=y;e[len].next=linkk[x];linkk[x]=len;e[len].back=len+1;e[len].flow=f;
    	e[++len].y=x;e[len].next=linkk[y];linkk[y]=len;e[len].back=len-1;e[len].flow=0;
    }
    inline bool getlevel(){
    	head=tail=0;
    	memset(level,-1,sizeof(level));
    	level[s]=0;q[++tail]=s;
    	while(head<tail){
    		int tn=q[++head];
    		for(int i=linkk[tn];i;i=e[i].next){
    			if(level[e[i].y]==-1&&e[i].flow){
    				level[e[i].y]=level[tn]+1;
    				q[++tail]=e[i].y;
    			}
    		}
    	}
    	return level[t]>=0;
    }
    inline int getmaxflow(int x,int flow){
    	if(x==t) return flow;
    	int f=0,d;
    	for(int i=linkk[x];i;i=e[i].next){
    		if(e[i].flow&&level[e[i].y]==level[x]+1){
    			if(d=getmaxflow(e[i].y,min(flow-f,e[i].flow))){
    				f+=d;e[i].flow-=d;e[e[i].back].flow+=d;
    				if(f==flow) return f;
    			}
    		}
    	}
    	if(f==0) level[x]=-1;
    	return f;
    }
    inline int dinic(){
    	int ans=0,d;
    	while(getlevel()){
    		while(d=getmaxflow(s,inf)) ans+=d;
    	}
    	return ans;
    }
    void build(){
    	memset(linkk,0,sizeof(linkk));len=0;
    	for(int i=1;i<=n;i++){
    		for(int j=1;j<=n;j++){
    			if(col[i][j]==1) insert(i,j,inf);
    			if(col[i][j]==0) insert(i,j,1);
    		}
    	}
    }
    int main(){
    	while(scanf("%d%d%d%d%d%d%d",&n,&a1,&a2,&an,&b1,&b2,&bn)!=EOF){
    		a1++,b1++,a2++,b2++;
    		s=0;t=n+1;
    	    for(int i=1;i<=n;i++){
    		    char ch[60];
    		    scanf("%s",ch+1);
    		    for(int j=1;j<=n;j++){
    			    if(ch[j]=='O') col[i][j]=0;
    			    if(ch[j]=='X') col[i][j]=-1;
    			    if(ch[j]=='N') col[i][j]=1;
    		    }
    	    }
    	    int flag=0;
    		build();
    	    insert(s,a1,an),insert(s,b1,bn);
    	    insert(a2,t,an),insert(b2,t,bn);
    	    int ans=dinic();
    	    if(ans<an+bn) flag=1;
    	    if(flag){
    	    	printf("No
    ");continue;
    		}
    		build();
    		insert(s,a1,an);insert(s,b2,bn);
    		insert(a2,t,an);insert(b1,t,bn);
    		ans=dinic();
    		if(ans<an+bn) flag=1;
    		if(flag) printf("No
    ");
    		else printf("Yes
    ");
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    List remove注意点
    枚举类比较的陷阱
    【好书推荐】《剑指Offer》之硬技能(编程题7~11)
    【好书推荐】《剑指Offer》之硬技能(编程题1~6)
    【好书推荐】《剑指Offer》之软技能
    在互联网中关系型数据库是否不再那么重要
    常用开发环境搭建配置教程(OneStall)
    让Mongo在Spring中跑起来
    MongoDB初了解——用户权限
    毕业这两年
  • 原文地址:https://www.cnblogs.com/something-for-nothing/p/8980912.html
Copyright © 2011-2022 走看看