[CQOI2014]危桥

题目描述

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

题解

有一个初步的想法,因为图是无向的,所以我们的往返可以看做走两遍。

所以我们就把无向图连出来,然后连上源和汇跑一遍最大流,然后检查是否漫流。

但这样会有一个问题,两股流有可能会有交叉的地方,这样我们有可能会把无解判断成有解。

也就是\(s1->t2\ s2->t1\)

正解非常巧妙,就是把一条路径反过来再跑一遍,如果还漫流,则说明有解。

为什么,这时如果还满流,那么会有\(s1->s2\ t2->t1\)那么这说明\(s1\)是这股流是可以到\(t1\)的,\(s2\)也是可以到\(t2\)的,则它是有解的。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define N 60
#define inf 1e9
using namespace std;
queue<int>q;
int head[N],tot=1,cur[N],deep[N],n,ans;
char s[N][N];
inline int rd(){
    int x=0;char c=getchar();bool f=0;
    while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
    while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    return f?-x:x;
}
struct edge{
	int n,to,l;
}e[N*N*10];
inline void add(int u,int v,int l){
    e[++tot].n=head[u];e[tot].to=v;head[u]=tot;e[tot].l=l;
    e[++tot].n=head[v];e[tot].to=u;head[v]=tot;e[tot].l=l;
}
bool bfs(int s,int t){
    memcpy(cur,head,sizeof(head));
    memset(deep,0,sizeof(deep));
    q.push(s);deep[s]=1;
    while(!q.empty()){
        int u=q.front();q.pop();
        for(int i=head[u];i;i=e[i].n){
            int v=e[i].to;
            if(!deep[v]&&e[i].l){
                deep[v]=deep[u]+1;
                q.push(v);
            }
        }
    }
    return deep[t];
}
int dfs(int u,int t,int l){
    if(u==t||!l)return l;
    int flow=0,f;
    for(int &i=cur[u];i;i=e[i].n){
      int v=e[i].to;
      if(deep[v]==deep[u]+1&&(f=dfs(v,t,min(l,e[i].l)))){
      	  e[i].l-=f;e[i^1].l+=f;flow+=f;l-=f;
      	  if(!l)break;
      }
    }
    return flow;
}
int main(){
	int a1,a2,an,b1,b2,bn;
	while(scanf("%d",&n)!=EOF){
		a1=rd()+1;a2=rd()+1;an=rd();b1=rd()+1;b2=rd()+1;bn=rd();;
		for(int i=1;i<=n;++i)scanf("%s",s[i]+1);
		tot=1;
		memset(head,0,sizeof(head));
		for(int i=1;i<=n;++i)
		  for(int j=1;j<i;++j)
		    if(s[i][j]=='N')add(i,j,inf);
		    else if(s[i][j]=='O')add(i,j,1);
		add(0,a1,an);add(0,b1,bn);
		add(a2,n+1,an);add(b2,n+1,bn);ans=0;
		while(bfs(0,n+1))ans+=dfs(0,n+1,inf);
		if(ans!=an+bn){puts("No");continue;}
		tot=1;
		memset(head,0,sizeof(head));
		for(int i=1;i<=n;++i)
		  for(int j=1;j<i;++j)
		    if(s[i][j]=='N')add(i,j,inf);
		    else if(s[i][j]=='O')add(i,j,1);
		add(0,a1,an);add(0,b2,bn);
		add(a2,n+1,an);add(b1,n+1,bn);ans=0;
		while(bfs(0,n+1))ans+=dfs(0,n+1,inf);
		if(ans!=an+bn){puts("No");continue;}
		puts("Yes");
	}
	return 0;
}
posted @ 2019-03-20 08:45  comld  阅读(201)  评论(0编辑  收藏  举报