1.题目链接。题目大意:N个湖之间有M条河连接,每个湖有一个数字,现在有一个这样的需求,要求经过所有的河一次,并且要求在这个路径上的所有湖的数字异或起来最大。
2.首先分析第一个条件,经过所有边一次,那么就是欧拉通路问题了,这个问题我们很清楚,在无向图中对每个顶点的度数进行统计,只要是奇数度数的顶点是0个或者两个,那么就存在欧拉通路,如果是0个,就是欧拉回路。(注意,不可能出现1个。因为出现一个度数为奇数的顶点表明这个图是不连通的,一个不连通的图就没有什么欧拉路径可言了)。然后是第二个条件,经过的所有的值异或起来最大,我们知道,一个数被连续的异或两次,那么等于没有任何作用。首先我们分析奇数度数为2个的时候,这个时候,是存在欧拉通路的,这个两个奇数度数的顶点作为起点和终点。那么我们对所有点的度数进行统计,注意,这里统计的度数是出度和入度之和,但是我们经过一个点的时候,这个点的出度和入度就会+2,所以我们真正经过这个点的次数,就是(度数+1)/2.我们刚才知道,一个属被连续异或两次,等于没有作用,所以我们需要判断这个处理后的度数是不是一个奇数,如果是奇数,那么他对答案有作用,否则直接跳过。这个看似简单的优化,其实作用很大,没有他就会TLE。如果是欧拉回路,那么走完所有的边一定会回到起点,所以这个时候,我们的起起点就会被多算一次。那么这个时候最值就来了,到底从哪出发?这个时候,我们首先枚举所有的情况,注意这里的枚举也是像刚才那样的枚举,否则还是会T。在这种情况下,我们最后枚举起点,维护最大值。得到答案。这里我们需要注意一个坑点,就是文章开头提到的,图的联通性,这里的图是有可能不连通的,所以我们需要判断。至于判断无向图的连通,并查集即可。Show code:
#include<bits/stdc++.h>
using namespace std;
const int max_n = 1e5 + 5;
int v[max_n];
int w[max_n];
int f[max_n];
#pragma warning(disable:4996)
int find(int a)
{
return f[a] == a ? a : f[a] = find(f[a]);
}
void join(int a, int b)
{
f[find(a)] = find(b);
}
int main()
{
int t;
int n, m;
scanf("%d", &t);
while (t--)
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
{
f[i] = i;
}
for (int i = 1; i <= n; i++)
{
scanf("%d", w + i);
}
int a, b;
memset(v, 0, sizeof(v));
for (int i = 0; i < m; i++)
{
scanf("%d%d", &a, &b);
join(a, b);
v[a]++;
v[b]++;
}
int flag = 0;
for (int i = 2; i <= n; i++)
{
if (find(i) != find(1))
{
puts("Impossible");
flag = 1;
break;
}
}
if (flag)
{
continue;
}
int cnt = 0;
for (int i = 1; i <= n; i++)
{
if (v[i] & 1)
{
cnt++;
}
}
if (cnt > 2)
{
puts("Impossible");
}
else if (cnt == 2)
{
int ans = 0;
for (int i = 1; i <= n; i++)
{
v[i] = (v[i] + 1) / 2;
if (v[i] & 1)
{
ans ^= w[i];
}
}
printf("%d\n", ans);
}
else if (cnt == 0)
{
int ans = 0;
for (int i = 1; i <= n; i++)
{
v[i] = v[i] / 2;
if (v[i] & 1)
{
ans ^= w[i];
}
}
int ans2 = ans ^ w[1];
for (int i = 2; i <= n; i++)
{
ans2 = max(ans2, ans^w[i]);
}
printf("%d\n", ans2);
}
}
return 0;
}