hdu5883 The Best Path (异或和最大的欧拉路)

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

题意:

给定无向图,每个节点都有权值,求欧拉路(或欧拉回路),
使得路径上经过节点的权值异或和最大,输出这个最大值。

分析:

欧拉路每个节点经过的次数为 该点的度/2
起点和终点多走一次 (回路则起点多走一次)
根据异或的性质,偶数次的异或值为0,因此只有经过次数为奇数次才对答案有贡献
我们先统计每个点的度

1 .如果所有点的度数都为偶数,则为欧拉回路,
先把所有点的 异或值计算起来 (经过奇数次的点才有贡献)
因为起点多走一次,我们枚举起点,再把前面求出来的数值异或上起点,找到最大值就行了。

2 .如果只有两个点的度数为奇数,则为欧拉路
和前面一样要把所有点的 值异或起来 (经过奇数次的点才有贡献),
因为起点和终点多走一次,所以我们遇到 度为奇数的点,经过次数加1 之后再判断是否对答案有贡献
最后输出即可

code:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<stack>
#include<algorithm>
const int inf=0x3f3f3f3f;
const int inn=0x80808080;
using namespace std;
const int maxm=1e5+5;
int d[maxm];
int p[maxm];
int n,m;
void init(){
    memset(d,0,sizeof d);
}
void input(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%d",&p[i]);
    }
    for(int i=1;i<=m;i++){
        int a,b;
        scanf("%d%d",&a,&b);
        d[a]++;
        d[b]++;
    }
}
void solve(){
    int odd=0;
    for(int i=1;i<=n;i++){
        if(d[i]%2)odd++;
    }
    if(odd!=0&&odd!=2){//如果没有欧拉路
        puts("Impossible");
        return ;
    }
    //否则有欧拉路
    int ans=0;
    for(int i=1;i<=n;i++){//每个点的访问次数为d/2
        int t=d[i]/2;
        if(d[i]%2){//奇数度的点是起点或者终点,访问次数多一次
            t++;
        }
        if(t%2)ans^=p[i];//奇数次的点才有贡献
    }
    if(odd==2){//不是回路的情况直接输出答案
        printf("%d\n",ans);
        return ;
    }
    //否则是回路的情况,枚举起点
    int temp=ans;;
    for(int i=1;i<=n;i++){//起点多走一次
        ans=max(ans,temp^p[i]);
    }
    printf("%d\n",ans);
}
int main(){
//    ios::sync_with_stdio(0);
    int T;
    scanf("%d",&T);
    while(T--){
        init();
        input();
        solve();
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值