zoukankan      html  css  js  c++  java
  • 【CQOI2014】危桥

    【CQOI2014】危桥

    Description

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

    Input

    本题有多组测试数据。
    每组数据第一行包含7个空格隔开的整数,分别是(N,a1,a2,an,b1,b2,bn)
    接下来是一个N行N列的对称矩阵,由大写字母组成。矩阵的第i行第j列描述编号i-1和j-1的岛屿间连接情况,若为“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

    网络流。

    首先因为是走来回,所以我们就每找到一条路径就原路返回。所以危桥的容量变成1。

    然后我们建((S,a1,an),(S,b1,bn))以及((a2,T,an),(b2,T,bn))。其他的边照常建。

    如果满流就能证明可行吗?

    反例就是(a1)流向(b2)(b1)流向(a2)

    于是我们交换(b1,b2),再跑一边网络流,仍然满流就成立。

    交换过后万一还是出现了上述的反例呢?我们发现,如果出现这种情况,那么一定有足够的(a1)(a2)(b1)(b2)的流量。

    代码:

    #include<bits/stdc++.h>
    #define ll long long
    #define N 55
    
    using namespace std;
    inline int Get() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;}
    
    int n,a[N][N];
    int a1,a2,b1,b2;
    int an,bn;
    struct load {
    	int to,next;
    	int flow;
    }s[N*N<<1];
    int h[N],cnt;
    void add(int i,int j,int f) {
    	s[++cnt]=(load) {j,h[i],f};h[i]=cnt;
    	s[++cnt]=(load) {i,h[j],0};h[j]=cnt;
    }
    void Init() {
    	cnt=1;
    	memset(h,0,sizeof(h));
    }
    int S,T;
    int dis[N],gap[N];
    int dfs(int v,int maxf) {
    	if(v==T) return maxf;
    	int ret=0;
    	for(int i=h[v];i;i=s[i].next) {
    		int to=s[i].to;
    		if(s[i].flow&&dis[to]+1==dis[v]) {
    			int dlt=dfs(to,min(maxf,s[i].flow));
    			s[i].flow-=dlt;
    			s[i^1].flow+=dlt;
    			ret+=dlt;
    			maxf-=dlt;
    			if(!maxf||dis[S]==n+2) return ret;
    		}
    	}
    	if(!(--gap[dis[v]])) dis[S]=n+2;
    	gap[++dis[v]]++;
    	return ret;
    }
    
    bool sap(int a1,int a2,int an,int b1,int b2,int bn) {
    	Init();
    	add(S,a1,an),add(S,b1,bn);
    	add(a2,T,an),add(b2,T,bn);
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=n;j++)
    			if(a[i][j]==1) add(i,j,1);
    			else if(a[i][j]==2) add(i,j,1e9);
    	memset(dis,0,sizeof(dis));
    	memset(gap,0,sizeof(gap));
    	gap[0]=n+2;
    	int ans=0;
    	while(dis[S]<=n+2) ans+=dfs(S,1e9);
    	return ans==an+bn;
    }
    
    int main() {
    	while(scanf("%d",&n)!=EOF) {
    		a1=Get()+1,a2=Get()+1,an=Get();
    		b1=Get()+1,b2=Get()+1,bn=Get();
    		char x;
    		S=0,T=n+1;
    		for(int i=1;i<=n;i++) {
    			for(int j=1;j<=n;j++) {
    				while(x=getchar(),x!='X'&&x!='O'&&x!='N');
    				if(x=='O') a[i][j]=1;
    				else if(x=='N') a[i][j]=2;
    				else a[i][j]=0;
    			}
    		}
    		int flag=0;
    		if(sap(a1,a2,an,b1,b2,bn)) {
    			swap(b1,b2);
    			flag=sap(a1,a2,an,b1,b2,bn);
    		}
    		(flag)?cout<<"Yes
    ":cout<<"No
    ";
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    一篇文章让你了解GC垃圾回收器
    使用SpringBoot整合ssm项目
    SpringBoot项目集成Hystrix
    50个简单易懂的经济学定律
    使用POI导出EXCEL工具类并解决导出数据量大的问题
    数据库事务的四大特性以及四种隔离级别
    简单了解Redis
    如何更规范化的编写JAVA 代码
    如何在Linux服务器上部署Mysql
    常见的数据库函数,关键字整理
  • 原文地址:https://www.cnblogs.com/hchhch233/p/10367220.html
Copyright © 2011-2022 走看看