bzoj3504 危桥

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

网络流。

那么关键就是如何建图。

这道题只需要根据图中说的建图就行了,很经典的一种建图方法。不多说了。

那么这道题的关键是在哪里呢?关键就是制作一遍会有问题。

比如从a1万一到不了a2,然而最终流到了b2,这样显然是不可行的。

那么我们可以把b1和b2反一下再做一遍,如果还是满流就可以了。

那么这道题就愉快的解决了。

代码:

#include <bits/stdc++.h>
#define N 110
#define M 100010
#define INF 0x7f7f7f7f
#define T 51
using namespace std;

struct Edge
{
	int to, next, v;
}e[M];
int head[M], cur[M], a[N][N], h[N], q[N]; 
int cnt, flag;
int n, a1, a2, an, b1, b2, bn, ans;

void ins(int u, int v, int w)
{
	e[++ cnt].to = v;
	e[cnt].next = head[u];
	head[u] = cnt;
	e[cnt].v = w;
}

void insert(int u,int v,int w)
{
	ins(u, v, w);
	ins(v, u, 0);
}

void build()
{
	memset(head, 0, sizeof(head));
	cnt = 1;
	for(int i = 1; i <= n; i ++)
		for(int j = 1; j <= n; j ++)
			if(a[i][j] == 1) insert(i, j, 2);
			else if(a[i][j] == 2) insert(i, j, INF);
}

int dfs(int x, int f)
{
	if(x == T) return f;
	int w, used = 0;
	for(int i = cur[x]; i; i = e[i].next)
	{
		if(e[i].v && h[e[i].to] == h[x] + 1)
        {
            w = f - used;
            w = dfs(e[i].to,min(e[i].v,w));
            e[i].v -= w;
            if(e[i].v) cur[x] = i;
            e[i ^ 1].v += w;
            used += w;
			if(used == f)return f;
        }
	}
	if(used == 0) h[x] = -1;
	return used;
}

int bfs()
{
	int t = 0, w = 1;
	for(int i = 0; i <= T; i ++)
		h[i] = -1;
	h[t] = 0;
	q[t] = 0;
	while(t != w)
	{
		int now = q[t];
		t ++;
		for(int i = head[now]; i; i = e[i].next)
			if(e[i].v && h[e[i].to] == -1)
			{
				h[e[i].to] = h[now] + 1;
				q[w ++] = e[i].to; 
			}
	}
	if(h[T] == -1) return 0;
	else return 1;
}

void dinic()
{
	while(bfs())
	{
		for(int i = 0; i <= T; i ++)
			cur[i] = head[i];
		ans += dfs(0, INF);
	}
}

int main()
{
	while(scanf("%d%d%d%d%d%d%d", &n, &a1, &a2, &an, &b1, &b2, &bn) != EOF)
	{
		memset(a, 0, sizeof(a));
		a1 ++;
		a2 ++;
		b1 ++;
		b2 ++;
		flag = 0;
		for(int i = 1; i <= n; i ++)
		{
			char ch[55];
			scanf("%s",ch);
			for(int j = 1; j <= n; j ++)
				if(ch[j - 1] == 'O') a[i][j] = 1;
				else if(ch[j - 1] == 'N') a[i][j] = 2;
		}
		build();
		insert(0, a1, an * 2);
		insert(a2, T, an * 2);
	    insert(0, b1, bn * 2);
		insert(b2, T, bn * 2);
		ans = 0;
		dinic(); 
		if(ans < 2 * (an + bn))flag = 1;
		if(!flag)
		{
		    build();
	    	insert(0, a1, an * 2);
			insert(a2, T, an * 2);
	    	insert(0, b2, bn * 2);
			insert(b1, T, bn * 2);
	    	ans = 0;
	    	dinic();
	    	if(ans < 2 * (an + bn)) flag = 1;
		}
		if(flag)printf("No\n");
		else printf("Yes\n");
	}
	
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值