题意:给出一个无向图,问是否存在欧拉路(一笔画),问经过最大的顶点异或和
思路:这题完全是考察欧拉路的性质,所以先来回顾下欧拉路的性质
对于一个图是否存在欧拉路,首先要判断它的连通性,判断连通性可以用并查集或者bfs,dfs,这道题用了并查集
对于无向图
存在欧拉路径的充要条件是度数为奇数的点的个数有且仅有两个,并且必须从其中一个奇点出发,另一个奇点结束
存在欧拉回路的充要条件是不存在度数为奇数的点,并且从任意点出发,最终一定会回到该点
对于有向图
存在欧拉路径的充要条件是有两个点的入度不等于出度,而且必须是其中一个点的出度恰好比入度大一(此点当做起点),另个一的入度比出度大一(当做终点)
存在欧拉路径的充要条件是所有点的入度等于出度
对于这道题是一个无向图,那么判断无向图的充要条件即可,可能是欧拉路径,也可能是欧拉回路。
细节看代码
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 100005;
struct edge
{
int u, v, next;
} e[5000005];
int head[maxn], cnt;
void init()
{
cnt = 0;
memset(head, -1, sizeof(head));
}
void addedge(int u, int v)
{
e[cnt].u = u, e[cnt].v = v, e[cnt].next = head[u], head[u] = cnt++;
}
int p[maxn], a[maxn];
int degree[maxn];//每个顶点的度数
int Find(int x)
{
return x == p[x] ? x : p[x] = Find(p[x]);
}
void solve(int n)
{
int res = 0;
for(int i = 1; i <= n; i++)
{
if(degree[i] & 1)
res++;
if(res >= 3) break;
}
if(res == 0)//欧拉回路
{
int ans1 = 0, ans2;
for(int i = 1; i <= n; i++)
if((degree[i] / 2) & 1)//中间顶点的度数/2是个奇数,表明经过这个点奇数次,而异或自己只有奇数次才有效
ans1 ^= a[i];
ans2 = ans1;
for(int i = 1; i <= n; i++)//从任意一个点出发的得到的最大值
if((degree[i] / 2) & 1)
ans2 = max(ans2, ans1 ^ a[i]);
printf("%d\n", ans2);
}
else if(res == 2)//欧拉路径
{
int ans = 0;
for(int i = 1; i <= n; i++)
{
if(degree[i] & 1) //起点和终点必然奉献一次
{
ans ^= a[i];
continue;
}
if((degree[i] / 2) & 1)//中间顶点的度数/2是个奇数,表明经过这个点奇数次,而异或自己只有奇数次才有效
ans ^= a[i];
}
printf("%d\n", ans);
}
else //不存在欧拉路
puts("Impossible");
}
int main()
{
int t, n, m;
scanf("%d", &t);
while(t--)
{
init();
memset(degree, 0, sizeof(degree));
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++)
{
p[i] = i;
scanf("%d", &a[i]);
}
for(int i = 0; i < m; i++)
{
int u, v;
scanf("%d%d", &u, &v);
addedge(u, v);
addedge(v, u);
degree[u]++, degree[v]++;
int fx = Find(u), fy = Find(v);
if(fx != fy)
p[fx] = fy;
}
int res = Find(1);
bool flag = false;
for(int i = 1; i <= n; i++)
{
if(res != Find(i))
{
flag = true;
break;
}
}
if(flag)//这个图不连通
{
puts("Impossible");
continue;
}
solve(n);
}
return 0;
}