The Best Path ( 欧拉图 及其性质 )
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
题意:有n个湖泊, m条小河, 每条小河连接两个湖泊。 现在Alice想要从一个湖泊出发坐着小船经过所有的小河一次且仅一次,如果可能输出经过点的异或和( p0→p1→p2 == p0 xor p1 xor p2 ), 不可能输出Impossible。
前言:
1. 欧拉路:欧拉路是指从图中任意一个点开始到图中任意一个点结束的路径,并且图中每条边通过的且只通过一次。
2. 欧拉回路:欧拉回路是指起点和终点相同的欧拉路。
3. 一个无向图存在欧拉路,当且仅当该图有0个或2个奇数度数的顶点,且该图是连通图。
4.一个无向图存在欧拉回路,当且仅当该图所有顶点度数都为偶数,且该图是连通图。
5.一个有向图存在欧拉回路,所有顶点的入度等于出度且该图是连通图。
6.一个有向图存在欧拉路:图连通,所有节点的出度等于入度;或者除两个节点以外的其余节点的入度和出度都相等,且这两个节点一个满足出度-入度==1,另一个满足入度--出度==1。
思路:这个题是个无向图判断是否是欧拉图。
首先,我们可以通过判断度的奇偶性来判断是否是 Impossible,因为欧拉路径存在两种,一种是欧拉通路,一种是欧拉回路。通路是起点、终点是不同点,那么我们需要将起点终点多算一次,并且起点和终点是固定的,必然是度为奇数的结点,那么我们也就知道了这种情况需要度为奇数的结点只有连个;回路呢,其实是起点、终点重合,变成了同一个点,所以呢,我们需要对这个起点多算一次即可了,但是这里起点不唯一,所以需要枚举起点。
那么问题来了,每个结点的异或次数是多少呢?实际上这个和度有关,因为我们可以想象的到的是,每次经过一个结点,除了起点和终点外,必然是一个入度和一个出度,想要让每条路都走一遍,需要把这些度都消费掉,那么每个结点的异或次数自然就是度数的一半了,然而这里还要一个小小的优化就是,异或不管次数再多,只有两种结果,一种是异或奇数次,一种是异或偶数次,因为偶数次的异或会抵消异或的效力,酱紫就好做很多了。这里需要注意的是,起点和终点多算一次异或也就行了。
所以呢,这里的第一个过程不考虑起点时,求得一个异或值后,接着在第二个过程加入起点和终点,如果是通路,就是固定起点和终点,比较容易解决,回路就需要遍历求最大值,而这里我们需要注意的是,插入起点后,结果可能比第一个过程的临时结果大,也可能小,所以需要格外注意取最的过程,不要以为只会变大哦~~~ ( 思路转载自肘子zhouzi )
代码:没判定图是否是连通的就给过了,可能数据全是连通图的
#include<bits/stdc++.h>
using namespace std;
const int maxn = 5e5+10;
int head[maxn];
int cnt,date[maxn],n,m;
int du[maxn];
int main()
{
int listt;
cin >> listt;
while ( listt-- ) {
memset(du,0,sizeof(du));
memset(date,0,sizeof(date));
cnt = 0;
cin >> n >> m;
for ( int i=1; i<=n; i++ ) {
scanf("%d",&date[i]);
}
for ( int i=0; i<m; i++ ) {
int u,v;
scanf("%d %d",&u,&v);
du[u] ++; du[v] ++;
}
int tot = 0,x1,x2;
for ( int i=1; i<=n; i++ ) {
if ( du[i]%2==1 ) {
tot ++;
du[i] ++; // 奇数度节点一定是起点或者终点,所有加一个进入和退出的度
}
}
int ans = 0;
for ( int i=1; i<=n; i++ ) {
if ( du[i]/2%2==1 ) { // 度数/2 是当前点会被便利几次, %2 是只有奇数次来会进行操作
ans ^= date[i];
}
}
if ( tot==1||tot>=3 ) {
printf("Impossible\n");
}
else if ( tot==2 ) {
cout << ans << endl;
}
else {
int maxx = ans;
for ( int i=1; i<=n; i++ ) { // 从哪个点开始走,这个点就多算一次。 所有总值再异或一次。
maxx = max(maxx,ans^date[i]);
}
cout << maxx << endl;
}
}
return 0;
}