(intermediate) UVA 带下界的网络流 1369 - Travel

Kim works in a traveling agency in Korea. Recently, his foreign customer gave him an international call and asked him to make a travel plan in Korea. The customer wants to visit two famous roads along which beautiful flowers are in full blossom. The customer would like to fly to a city in the plan and rent a car, enjoy his travel, and return to the city where he started. He does not want to visit the same city or the same road twice. Also, he hates to travel along any toll roads. It does not matter how many cities are included in the plan. Can Kim make a travel plan satisfying the requirements? For example, see the maps in Figure 1. In the figure a circle represents a city and the line between two cities represents the road between them. The two bold lines represent the famous roads that the customer wants to visit and the dotted line is a toll road.

\epsfbox{p3604.eps} Figure 1
In case of Figure 1(a), Kim can make travel plans such as 1 $ \rightarrow$ 2 $ \rightarrow$ 4 $ \rightarrow$ 5 $ \rightarrow$ 3 $ \rightarrow$ 1 and 2 $ \rightarrow$ 3 $ \rightarrow$ 5 $ \rightarrow$ 4 $ \rightarrow$ 2 . In case of Figure 1(b), Kim can not make any plan satisfying the requirements. You are to write a program to help Kim. For a given map with two famous roads and some toll roads, your program should determine whether there can be a travel plan satisfying the requirements.

Input 

Your program is to read from standard input. The input consists of T test cases. The number of test cases T is given in the first line of the input. Each test case starts with a line containing two integers N and M , the number of cities and the number of roads in the map, respectively, where 5$ \le$N$ \le$1000 . In the next M lines, each line contains two positive integers that represent a road connecting two cities. In the next two lines, each line contains a road that the customer wants to visit. In the next line, the number of toll roads F is given, 0$ \le$F$ \le$M . In the next F lines, each line contains toll roads. Assume the cities are labeled from 1 to N and there is at most one road between two cities. Also, assume the two roads that the customer wants to visit are not toll roads.

Output 

Your program is to write to standard output. Print exactly one line for each test case. For each test case, print YES if there can be a travel plan satisfying the requirements. Otherwise, print NO. The following shows sample input and output for three test cases.

Sample Input 

3 
6 8
2 1
1 3
4 5
2 4
5 3
2 3
3 6
5 6
3 5
2 4
1 
6 5
6 8
2 1
1 3
4 5
2 4
5 3
2 3
3 6
5 6
2 3
3 5
1 
4 2
5 4
1 2
2 3
3 4
4 5
1 2
4 5
2 
2 3
3 4

Sample Output 

YES 
NO 
NO


题意:给出一个无向图,然后某两条边是一定要经过的,并且每条边和每个点最多只能经过一次,你需要从某一个点出发,按上面的规则回到这个出发点,问这种路线存不存在。


思路:我们把每个点拆成两个点,一个表示出度,一个表示入度,然后他们之间连一条容量为1的边,如果图中存在一条边(u,v) 我们就把u的出度连到v的入度,最后我们根据要求有两条边的下界容量为1,于是我们对这两条边进行带下界容量的建图方式,然后起点是x1的出度,终点是x1的入度(假设x1是必须经过的一条边的某一个点),对于这个x1的出度和入度,不要连起来。  那么我们跑一次网络流,如果所有带下界的边满流,那么就存在一种方案了,否则就不存在。

。。。。我的代码能过UVA的,ZOJ的好像过不了。。。不知道哪里还有什么BUG


代码:

#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
#include<string.h>
#include<algorithm>
#include<cstring>
using namespace std;
const short inf = 1 << 14;
const int maxn = 2000 + 10;

struct Edge
{
	short u, v;
	short cap;
	short flow;
	Edge(short u, short v, short cap, short flow)
		:u(u), v(v), cap(cap), flow(flow) {}
};


vector<Edge> edges;
vector<int> G[maxn];


void add(short u, short v, short cap)
{
	edges.push_back(Edge(u, v, cap, 0));
	edges.push_back(Edge(v, u, 0, 0));
	int m = edges.size();
	G[u].push_back(m - 2);
	G[v].push_back(m - 1);
}


struct ISAP
{
	int d[maxn], p[maxn], num[maxn], cur[maxn];
	int n, s, t;
	void init(int n) { this->n = n; }

	int Augment()
	{
		int x = t, a = inf;
		while (x != s)
		{
			Edge&e = edges[p[x]];
			a = min(a, e.cap - e.flow);
			x = e.u;
		}
		x = t;
		while (x != s)
		{
			edges[p[x]].flow += a;
			edges[p[x] ^ 1].flow -= a;
			x = edges[p[x]].u;
		}
		return a;
	}


	void bfs()
	{
		for (int i = 0; i < n; ++i) d[i] = inf;
		queue<int> q;
		d[t] = 0;
		q.push(t);
		while (q.size())
		{
			int x = q.front(); q.pop();
			for (int i = 0; i<G[x].size(); ++i)
			{
				Edge&e = edges[G[x][i]];
				if (e.cap>0 || d[e.v] <= d[x] + 1) continue;
				d[e.v] = d[x] + 1;
				q.push(e.v);
			}
		}
	}


	int maxflow(int s, int t)
	{
		this->s = s, this->t = t;
		memset(num, 0, sizeof(num));
		memset(cur, 0, sizeof(cur));
		memset(d, 0, sizeof(d));
		bfs();
		for (int i = 0; i < n; ++i)
		if (d[i] != inf) ++num[d[i]];
		int flow = 0, x = s;
		while (d[s] < n)
		{
			if (x == t)
			{
				flow += Augment();
				x = s;
			}
			int ok = 0;
			for (int i = cur[x]; i<G[x].size(); ++i)
			{
				Edge&e = edges[G[x][i]];
				if (e.cap>e.flow&&d[e.v] + 1 == d[x])
				{
					ok = 1;
					cur[x] = i;
					p[e.v] = G[x][i];
					x = e.v;
					break;
				}
			}
			if (!ok)
			{
				int m = n - 1;
				for (int i = 0; i<G[x].size(); ++i)
				{
					Edge&e = edges[G[x][i]];
					if (e.cap>e.flow) m = min(m, d[e.v]);
				}
				if (--num[d[x]] == 0) break;
				++num[d[x] = m + 1];
				cur[x] = 0;
				if (x != s) x = edges[p[x]].u;
			}
		}
		return flow;
	}
}solver;

bool g[1010][1010];
int N, M;

inline int nodein(int x) { return 2 * x - 1; }
inline int nodeout(int x) { return 2 * x; }

void solve()
{
	memset(g, false, sizeof(g));
	scanf("%d%d", &N, &M);
	for (int i = 0; i < M; ++i)
	{
		int x, y; scanf("%d%d", &x, &y);
		while (x == y);
		g[x][y] = g[y][x] = true;
	}
	int x1, y1, x2, y2;
	scanf("%d%d", &x1, &y1);
	scanf("%d%d", &x2, &y2);
	g[x1][y1] = g[x2][y2] = false;
	g[y1][x1] = g[y2][x2] = false;
	int F; scanf("%d", &F);
	for (int i = 0; i < F; ++i)
	{
		int x, y; scanf("%d%d", &x, &y);
		g[x][y] = g[y][x] = false;
	}
	edges.clear();
	for (int i = 0; i < maxn; ++i) G[i].clear();
	for (int i = 1; i <= N; ++i)
	for (int j = i + 1; j <= N; ++j)
	{
		if (!g[i][j]) continue;
		add(nodeout(i), nodein(j), 1);
		add(nodeout(j), nodein(i), 1);
	}

	for (int i = 1; i <= N; ++i)
	if (i != x1) add(nodein(i), nodeout(i), 1);

	int s = 0, t = 2 * N + 1;
	add(s, nodeout(x1), 1), add(nodein(x1), t, 1);
	add(t, s, inf);

	int ss = 2 * N + 2, tt = 2 * N + 3;
	int minflow = 0;

	add(ss, nodein(y1), 1);
	add(nodeout(x1), tt, 1);
	++minflow;
	vector<Edge> tmp = edges;
	add(nodeout(x2), tt, 1);
	add(ss, nodein(y2), 1);
	++minflow;
	solver.init(tt + 1);
	int ret = solver.maxflow(ss, tt);
	/*cout << "minflow: " << minflow << endl;
	cout << "Maxflow: " << ret << endl;*/
	if (ret == minflow) { puts("YES"); return; }
	//cout << edges.size() << endl;
	for (int i = 0; i < 2; ++i)
	{
		Edge&e = edges.back();/*
		cout << G[e.v].back()<<" ";*/
		G[e.v].pop_back();
	/*	cout << G[e.u].back() << endl;*/
		G[e.u].pop_back();
		edges.pop_back();
		edges.pop_back();
	}
	edges = tmp;
	add(nodeout(y2), tt, 1);
	add(ss, nodein(x2), 1);
	ret = solver.maxflow(ss, tt);/*
	cout << "minflow: " << minflow << endl;
	cout << "Maxflow: " << ret << endl;*/
	if (ret == minflow) puts("YES");
	else puts("NO");
}


int main()
{
	int T; cin >> T;
	while (T--)
	{
		solve();
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值