hdu 3472 HS BDC (混合欧拉回路+最大流)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3472

IELTS is around the corner! love8909 has registered for the exam, but he still hasn’t got prepared. Now he decides to take actions. But when he takes out the New Oriental IELTS Vocabulary, he finds there are so many words. But love8909 doesn’t get scared, because he has got a special skill. If he can make a list with some meaningful words, he will quickly remember these words and will not forget them. If the last letter of some word Wa is the same as the first letter of some word Wb, then you can connect these two words and make a list of two words. If you can connect a word to a list, you will make a longer list.

While love8909 is making the list, he finds that some words are still meaningful words if you reverse them. For example, if you reverse the word “pat”, you will get another meaningful word “tap”.

After scanning the vocabulary, love8909 has found there are N words, some of them are meaningful if reversed, while others are not. Now he wonders whether he can remember all these words using his special skill.

The N-word list must contain every word once and only once.

 

 

Input

An integer T (T <= 50) comes on the first line, indicating the number of test cases.

On the first line of each test cases is an integer N (N <= 1000), telling you that there are N words that love8909 wants to remember. Then comes N lines. Each of the following N lines has this format: word type. Word will be a string with only ‘a’~’z’, and type will be 0(not meaningful when reversed) or 1(meaningful when reversed). The length of each word is guaranteed to be less than 20.
 

 

 

Output

The format of the output is like “Case t: s”, t is the number of the test cases, starting from 1, and s is a string.
For each test case, if love8909 can remember all the words, s will be “Well done!”, otherwise it’s “Poor boy!”
 

 

 

Sample Input

 

3 6 aloha 0 arachnid 0 dog 0 gopher 0 tar 1 tiger 0 3 thee 1 earn 0 nothing 0 2 pat 1 acm 0

 

 

Sample Output

 

Case 1: Well done! Case 2: Well done! Case 3: Poor boy!

 

网络流判混合路欧拉回路

关键是把图变成有向图再判断

容易知道如果是欧拉回路那么所有点的入度in,等于出度out

可以发现无向边(u,v),有向边(u,v)或是有向边(v,u),in[i]-out[i]的奇偶性不变

那我们就可以先假定无向边(u,v)变成有向边(u,v)

统计所有点的入出度

如果存在i,使得abs(in[i]-out[i])%2==1那么图不存在欧拉回路

对于in[i]>out[i]的点,说明i点需要多流出流量,建边(S,i)流量(in[i]-out[i])/2

对于in[i]<out[i]的点,说明i点需要多流入流量,建边(i,T)流量(out[i]-in[i])/2

对于所有无向边(u,v),建边(u,v)流量1

跑S->T的最大流,若满流即存在一种方法通过改变无向边的方向使得每个点的入度=出度(是不是类似于上下界可行流是否有解问题)

#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<queue>
using namespace std;
const int maxn = 2010;
const int inf = 0x3f3f3f3f;
struct node
{
	int u, v, cap, rev;
	node(int a, int b, int c) { v = a, cap = b, rev = c; }
};
vector<node>g[maxn];
int level[maxn], vis[maxn], iter[maxn];
int f[30], cnt[30];  //cnt是入度减去出度的值
char str[maxn][50];
int t, n, m, type;
void addedge(int u, int v, int w)
{
	g[u].push_back(node(v, w, g[v].size()));
	g[v].push_back(node(u, 0, g[u].size() - 1));
}
int find(int x)
{
	if (x == f[x])
	{
		return x;
	}
	else
	{
		return find(f[x]);
	}
}
void uin(int a, int b)
{
	int aa = find(a);
	int bb = find(b);
	if (aa != bb)
	{
		f[aa] = bb;
	}
	return;
}
void bfs(int st)
{
	queue<int>pq;
	pq.push(st);
	memset(level, -1, sizeof(level));
	level[st] = 0;
	while (!pq.empty())
	{
		int u = pq.front();
		pq.pop();
		for (int i = 0; i < g[u].size(); i++)
		{
			node &e = g[u][i];
			if (e.cap > 0 && level[e.v] < 0)
			{
				level[e.v] = level[u] + 1;
				pq.push(e.v);
			}
		}
	}
}
int dfs(int st, int ed, int f)
{
	if (st == ed)
	{
		return f;
	}
	for (int i = iter[st]; i < g[st].size(); i++)
	{
		node &e = g[st][i];
		if (e.cap > 0 && level[e.v] > level[st])
		{
			int d = dfs(e.v, ed, min(e.cap, f));
			if (d > 0)
			{
				e.cap -= d;
				g[e.v][e.rev].cap += d;
				return d;
			}
		}
	}
	return 0;
}
int maxflow(int st, int ed)
{
	int flow = 0;
	while (1)
	{
		bfs(st);
		if (level[ed] < 0)
		{
			return flow;
		}
		memset(iter, 0, sizeof(iter));
		int f;
		while ((f = dfs(st, ed, inf)) > 0)
		{
			flow += f;
		}
	}
	return flow;
}
int main()
{
	//freopen("C:/input.txt", "r", stdin);
	scanf("%d", &t);
	int cas = 1;
	while (t--)
	{
		scanf("%d", &n);
		for (int i = 0; i < maxn; i++)
		{
			g[i].clear();
		}
		for (int i = 0; i < 30; i++)
		{
			vis[i] = 0;
			f[i] = i;
			cnt[i] = 0;
		}
		for (int i = 0; i < n; i++)
		{
			scanf("%s%d", str[i], &type);
			int a = str[i][0] - 'a' + 1;
			int len = strlen(str[i]);
			int b = str[i][len - 1] - 'a' + 1;
			cnt[a]--, cnt[b]++;
			vis[a] = 1, vis[b] = 1;
			if (type)
			{
				addedge(b, a, 2);
			}
			uin(a, b);
		}
		int sum = 0;
		for (int i = 1; i <= 26; i++)
		{
			if (vis[i] && f[i] == i)
			{
				sum++;
			}
		}
		printf("Case %d: ", cas++);
		if (sum > 1)
		{
			printf("Poor boy!\n"); 
			continue;

		}
		int sum1 = 0, sum2 = 0, t1, t2;
		for (int i = 1; i <= 26; i++)
		{
			if (cnt[i] > 0 && cnt[i] % 2 == 1)
			{
				sum1++;
				t1 = i;
			}
			else if (cnt[i] < 0 && (-cnt[i]) % 2 == 1)
			{
				sum2++;
				t2 = i;
			}
		}
		if (sum1 == 1 && sum2 == 1)
		{
			addedge(t1, t2, 1);
		}
		else if (sum1 == 0 && sum2 == 0) {}
		else
		{
			printf("Poor boy!\n"); continue;
		}
		sum = 0;
		for (int i = 1; i <= 26; i++)
		{
			if (cnt[i] > 0)
			{
				sum += cnt[i];
				addedge(0, i, cnt[i]);
			}
			else if (cnt[i] < 0)
			{
				addedge(i, 27, -cnt[i]);
			}
		}
		int ans = maxflow(0, 27);
		if (sum == ans)
		{
			printf("Well done!\n");
		}
		else
		{
			printf("Poor boy!\n");

		}
	}
	return 0;
}

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值