hdu-5883(欧拉判断+枚举)

                                           The Best Path

Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)
Total Submission(s): 2179    Accepted Submission(s): 867


 

Problem Description

Alice is planning her travel route in a beautiful valley. In this valley, there are N lakes, and M rivers linking these lakes. Alice wants to start her trip from one lake, and enjoys the landscape by boat. That means she need to set up a path which go through every river exactly once. In addition, Alice has a specific number (a1,a2,...,an) for each lake. If the path she finds is P0→P1→...→Pt, the lucky number of this trip would be aP0XORaP1XOR...XORaPt. She want to make this number as large as possible. Can you help her?

 

 

Input

The first line of input contains an integer t, the number of test cases. t test cases follow.

For each test case, in the first line there are two positive integers N (N≤100000) and M (M≤500000), as described above. The i-th line of the next N lines contains an integer ai(∀i,0≤ai≤10000) representing the number of the i-th lake.

The i-th line of the next M lines contains two integers ui and vi representing the i-th river between the ui-th lake and vi-th lake. It is possible that ui=vi.

 

 

Output

For each test cases, output the largest lucky number. If it dose not have any path, output "Impossible".

 

 

Sample Input

 

2

3 2

3

4

5

1 2

2 3

4 3

1

2

3

4

1 2

2 3

2 4

 

 

Sample Output

 

2

Impossible

 

 

Source

2016 ACM/ICPC Asia Regional Qingdao Online

 

 

Recommend

wange2014

 

一、原题地址

点我传送

 

二、大致题意

   一个无向图,每个点有权值,选择从某一个点出发,使得一笔画经过所有的路,且使得经过的节点的权值异或运算最大。若存在这种通路则输出最大值,否则输出Impossible。

 

三、思路

  一笔画问题就是关于欧拉图的问题。首先应该判断整张图是否是连通的,这里可以用并查集或者DFS来检查。若图不连通,则肯定不能一笔画完成。其次欧拉图的性质,无向图中所有奇数度数的节点的和必定为0或者2。

  1、若奇数度数的节点数为0.那么无论从哪个节点作为节点出发都必然是能够完成一笔画的。且终点必然是起点。那么问题就转为了,讨论每个节点在途中被经历了多少次,很显然应该是(当前节点的度数/2)。并且我们知道异或同一个数偶数次相当于没有效果,那么,我们只需要统计那些途中经历了奇数次的节点就可以了。需要注意的是因为我们可以选择从图中任意的节点出发,而对于这个起点来说,实际上他是会被少计算一次经历的次数,也就是说我们在统计次数时应该给他加回去。所以这里需要枚举每个点可能成为起点的情况,然后更新最值。

2、若奇数度数的节点数为2那么其中一个必然为起点,另一个必然为终点。那么实际的操作就是和1一样。

 

四、代码

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<string>
#include<math.h>
#include<cmath>
#include<time.h>
#include<map>
#include<set>
#include<vector>
#include<queue>
#include<algorithm>
#include<numeric>
#include<stack>
const int inf = 0x3f3f3f3f;
#define LL long long 
const double EI = 2.718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178525166427;
const double PI = acos(-1.0);
using namespace std;


const int MAXM = 1e6 + 5;
int father[100005];
int cnt[100005];
int find(int x)
{
	if (father[x] == x)
		return x;
	else
		return father[x] = find(father[x]);
}
void Union(int x, int y)
{
	int rx, ry;
	rx = find(x);
	ry = find(y);
	father[rx] = ry;
}
typedef struct
{
	int v, next, cost;
}Edge;
int T;
int n, m;
int val[100005], inde[100005];
void init()
{
	for (int i = 1; i <= 100000; i++)father[i] = i;
	memset(inde, 0, sizeof(inde));
}
void read()
{
	scanf("%d %d", &n, &m);
	for (int i = 1; i <= n; i++)
		scanf("%d", &val[i]);
	init();
	for (int i = 1; i <= m; i++)
	{
		int u, v;
		scanf("%d %d", &u, &v);
		Union(u, v);
		inde[u]++, inde[v]++;
	}

}
void solve()
{
	if (n == 0)
	{
		printf("Impossible\n");
		return;
	}
	int fa = find(1);
	for (int i = 1; i <= n; i++)
	{
		if (find(i) != fa)
		{
			printf("Impossible\n");
			return;
		}
	}
	int num = 0;
	for (int i = 1; i <= n; i++)
	{
		if (inde[i] & 1)
			num++;
		if (num > 2)break;
	}
	if (num > 2 || num == 1)
	{
		printf("Impossible\n");
		return;
	}
	else if (num == 0)
	{
		int ans = 0;
		for (int i = 1; i <= n; i++)
		{
			cnt[i] = inde[i] / 2;
			if (cnt[i] & 1)
				ans ^= val[i];
		}
		int pu = -inf;
		for (int i = 1; i <= n; i++)
		{
			pu = max(pu, ans^val[i]);
		}
		printf("%d\n", pu);
	}
	else if (num == 2)
	{
		int ans = 0;
		for (int i = 1; i <= n; i++)
		{
			if (inde[i] & 1)
			{
				cnt[i] = (inde[i] + 1) / 2;
			}
			else
				cnt[i] = inde[i] / 2;
			if (cnt[i] & 1)
				ans ^= val[i];
		}
		printf("%d\n", ans);
	}
	return;
}
int main()
{
	scanf("%d", &T);
	while (T--)
	{
		read();
		solve();
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值