码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj3504【CQOI2014】危桥

时间:2016-04-10 15:05:36      阅读:146      评论:0      收藏:0      [点我收藏+]

标签:

3504: [Cqoi2014]危桥

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 1161  Solved: 587
[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



做了很多网络流,可是考试时还是想不出如何构图,就好像听了无数人生大道理,却依旧过不好这一生。

如果是危桥则连容量为2的双向边,否则就连容量为正无穷的双向边,然后s到a1和b1分别连容量为2*an和2*bn的边,a2和b2到t分别容量为2*an和2*bn的边。跑最大流,判断是否等于2*(an+bn)。

但是这样做有一点问题,就是a1可能会流到b2,b1可能会流到a2,这显然是错误的。

考虑再构建一次图:交换b1和b2,即s到a1和b2分别连容量为2*an和2*bn的边,a2和b1到t分别容量为2*an和2*bn的边。再跑一次最大流,判断是否等于2*(an+bn)。这样就解决了刚才的问题。

证明:http://www.cnblogs.com/zyfzyf/p/4193441.html




#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
#define F(i,j,n) for(int i=j;i<=n;i++)
#define D(i,j,n) for(int i=j;i>=n;i--)
#define ll long long
#define maxn 100
#define maxm 3000
#define inf 1000000000
using namespace std;
int n,a1,a2,an,b1,b2,bn,s,t,cnt,ans;
int head[maxn],cur[maxn],dis[maxn];
char ch[maxn][maxn];
struct edge_type{int next,to,v;}e[maxm];
inline void add_edge(int x,int y,int v1,int v2)
{
	e[++cnt]=(edge_type){head[x],y,v1};head[x]=cnt;
	e[++cnt]=(edge_type){head[y],x,v2};head[y]=cnt;
}
inline void build()
{
	memset(head,0,sizeof(head));
	cnt=1;
	F(i,1,n-1)
	{
		F(j,i+1,n)
		{
			if (ch[i][j]=='O') add_edge(i,j,2,2);
			else if (ch[i][j]=='N') add_edge(i,j,inf,inf);
		}
	}
}
inline bool bfs()
{
	queue<int> q;
	memset(dis,-1,sizeof(dis));
	dis[s]=0;q.push(s);
	while (!q.empty())
	{
		int x=q.front();q.pop();
		if (x==t) return true;
		for(int i=head[x];i;i=e[i].next)
		{
			int y=e[i].to;
			if (e[i].v&&dis[y]==-1)
			{
				dis[y]=dis[x]+1;
				q.push(y);
			}
		}
	}
	return false;
}
inline int dfs(int x,int f)
{
	int tmp,sum=0;
	if (x==t) return f;
	for(int &i=cur[x];i;i=e[i].next)
	{
		int y=e[i].to;
		if (e[i].v&&dis[y]==dis[x]+1)
		{
			tmp=dfs(y,min(e[i].v,f-sum));
			sum+=tmp;e[i].v-=tmp;e[i^1].v+=tmp;
			if (f==sum) return sum;
		}
	}
	if (!sum) dis[x]=-1;
	return sum;
}
inline void dinic()
{
	ans=0;
	while (bfs())
	{
		F(i,1,t) cur[i]=head[i];
		ans+=dfs(s,inf);
	}
}
int main()
{
	while (scanf("%d%d%d%d%d%d%d",&n,&a1,&a2,&an,&b1,&b2,&bn)!=EOF)
	{
		a1++;a2++;b1++;b2++;an*=2;bn*=2;
		F(i,1,n) scanf("%s",ch[i]+1);
		s=n+1;t=n+2;
		build();
		add_edge(s,a1,an,0);add_edge(a2,t,an,0);
		add_edge(s,b1,bn,0);add_edge(b2,t,bn,0);
		dinic();
		if (ans!=an+bn){puts("No");continue;}
		build();
		add_edge(s,a1,an,0);add_edge(a2,t,an,0);
		add_edge(s,b2,bn,0);add_edge(b1,t,bn,0);
		dinic();
		if (ans!=an+bn){puts("No");continue;}
		puts("Yes");
	}
}


bzoj3504【CQOI2014】危桥

标签:

原文地址:http://blog.csdn.net/aarongzk/article/details/51100531

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!