【题解:CQOI2014 | BZOJ 3504 危桥】

BZOJ传送门

洛谷传送门

3504: [Cqoi2014]危桥
Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 2003 Solved: 1021
[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
唉,Alice and Bob终于没有在博弈论里面出现了 他们为什么来网络流里搞事情???OI里已经没有一方净土了吗????。

分析(扯淡)
黄学长的博客里确实有很多好题啊,蒟蒻博主最近切的网络流和费用流的题都是从黄学长的博客里面找的题 找好题看题解贴代码一条龙。
听说当时重庆现场AC的人不是很多(好像是1个),可能是神仙大佬们承让了吧,或者说是蒟蒻博主并没有感受到此题的妙处,刚开始学网络流的博主觉得此题确实好,不过还是可以做一下。。。然后就AC了。

分析(真的)
读完题后想到网络流里的最大流不难,想到如何限制最大流为2an+2bn也不难,想到如何限制危桥通过次数也不难,重点就是如何排除这个特殊情况:a1流出的流可能会通过b2流向汇点。

正解:跑完一次最大流并记录最大流ans1,然后清空残量网络并将其还原为原来的网络,然后将b1连向汇点,源点连向b2,再跑一次,记录最大流ans2,若ans1=ans2=an2+bn2则说明可行,否则不行。
代码:

#include<bits/stdc++.h>
using namespace std;
inline int read(){
	int flag=1;char ch;
	while((ch=getchar())<'0'||ch>'9') if(ch=='-') flag=-1;
	int ans=ch-48;
	while((ch=getchar())>='0'&&ch<='9') ans=ans*10+ch-48;
	return ans*flag;
}
inline void write(int x){
	if(x<0) putchar('-'),x=-x;
	if(x>9) write(x/10);
	putchar('0'+x%10);
	return;
}
const int N=60;
const int M=3001;
const int INF=0x7fffffff-1;
int n,a1,a2,an,b1,b2,bn;
int ans1,ans2,s,t;
int cnt=1,num=0,head[60],dep[60],cur[60];
struct node{
	int v,c,nt;
}e[M<<1];
struct node1{
	int  u,v,w;
}lst[M];
inline void add(int u,int v,int c){	
	cnt++;e[cnt]=(node){v,c,head[u]};head[u]=cnt;	
	cnt++;e[cnt]=(node){u,0,head[v]};head[v]=cnt;
}
inline void clean(){
	memset(head,0,sizeof(head));
	memset(e,0,sizeof(e));
	cnt=1;
}
inline bool bfs(){
	memset(dep,-1,sizeof(dep));
	queue<int >q;
	q.push(s);dep[s]=1;
	while(!q.empty()){
		int u=q.front();q.pop();
		for(int i=head[u];i;i=e[i].nt){
			int v=e[i].v;
			if(e[i].c&&dep[v]==-1){
				dep[v]=dep[u]+1;
				if(v==t) return 1;
				q.push(v);
			}
		} 
		 
	}
	return 0;
}
inline int dfs(int x,int f){
	if(x==t||f==0) return f;
	int used=0;
	for(int &i=cur[x];i;i=e[i].nt){
		int v=e[i].v;
		if(e[i].c&&dep[v]==dep[x]+1){
			int w=dfs(v,min(e[i].c,f));
			if(!w) continue;
			used+=w;
			f-=w;
			e[i].c-=w;e[i^1].c+=w;
			if(f==0) break;
		}
	}
	if(!used) dep[x]=-1;
	return used;
}
inline int dinic(){
	int ans=0;
	while(bfs()) {
		memcpy(cur,head,sizeof(head));
		ans+=dfs(s,INF);
	}
	return ans;
}
int main(){
	while(scanf("%d",&n)!=EOF){
		s=n+1,t=n+2;
		a1=read()+1,a2=read()+1,an=read()*2;
		b1=read()+1,b2=read()+1,bn=read()*2;
		memset(lst,0,sizeof(lst));
		num=0;
		char ch[N];
		for(int i=1;i<=n;i++){
			scanf("%s",ch+1); 
			for(int j=1;j<=n;j++){
				if(ch[j]=='X') continue;
				if(ch[j]=='O') lst[++num]=(node1){i,j,2};
				if(ch[j]=='N') lst[++num]=(node1){i,j,INF};
			}
		} 
		clean();
		for(int i=1;i<=num;i++)  
			add(lst[i].u,lst[i].v,lst[i].w);
		add(s,a1,an);add(s,b1,bn);
		add(a2,t,an);add(b2,t,bn);	
		ans1=dinic();
		clean();
		for(int i=1;i<=num;i++)
			add(lst[i].u,lst[i].v,lst[i].w);
		add(s,a1,an);add(s,b2,bn);
		add(a2,t,an);add(b1,t,bn);
		ans2=dinic();
		if(ans1==an+bn&&ans2==an+bn) printf("Yes\n");
		else printf("No\n");
	}
	return 0;
} 
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值