HDU 5883 The Best Path(並查集+歐拉回路 or 歐拉路)——2016 ACM/ICPC Asia Regional Qingdao Online

此文章可以使用目錄功能喲↑(點擊上方[+])

 HDU 5883 The Best Path

Accept: 0    Submit: 0
Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)

 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 aP0 XOR aP1 XOR ... XOR aPt. 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

 Problem Idea

解題思路:

【題意】
n個點,每個點有一個值ai,m條邊

Alice從某個點出發,恰好經過每條邊一次

問Alice走過的路線中,所經過的點的異或值最大爲多少

【類型】
並查集+歐拉回路 or 歐拉路
【分析】
首先,題目要求每條邊恰好經過一次

那我們暫且先不管如何能使點的異或值最大

單純考慮怎樣才能經過每條邊恰好一次

這考查的無疑是歐拉回路 or 歐拉路

那如何判斷圖中是否存在歐拉回路 or 歐拉路呢?

這個是有一個定理的

無向圖存在歐拉回路的充要條件:無向圖G具有一條歐拉回路,當且僅當G是連通的,並且所有結點度數全爲偶數。

無向圖存在歐拉路的充要條件:無向圖G具有一條歐拉路,當且僅當G是連通的,且有零個或兩個奇數度結點。

可見歐拉回路和歐拉路都和結點的度數有關,且圖還需是連通的

但是貌似這道題數據比較水,網上很多人的題解都沒有判是否連通,比如下列這種情況,不判連通顯然是過不了的


如圖所示,不管選取哪個點,都無法恰好經過每條邊一次

那判連通的話,並查集就能實現了

考慮完"Impossible"的情況之後,我們需要來求解如何才能使經過的點異或值最大

分兩種情況:

①圖中存在兩個奇數度結點

這種情況下,圖中存在歐拉路,路線的起點和終點分別是那兩個奇數度結點,如下圖


起點是結點8,終點是結點6

當然,起點是結點6,終點是結點8也是可以的


不過,不管是哪種走法,我們都可以發現

對於偶數度結點,假設度數爲k,那麼走的路線中必定會經過該點k/2次

比如說某點度數爲4,那麼必定要到達該點2次,從這點出去2次,這樣才能保證與該點相連的四條邊都走到

再考慮到異或運算中,一個數x,它異或本身的值等於0,即x^x=0

那我們只要考慮k/2是奇數還是偶數就可以了,偶數的話,意味着該點對異或值的貢獻爲0,否則貢獻爲a[i]

另外,最重要的一點是,歐拉路的起點和終點(即奇數度結點)會多貢獻一次,要記得計算在內

②圖中所有結點度數全爲偶數

這種情況下,圖中具有歐拉回路,這意味着路線必定是從某點出發再回到該點


這種情況其實與歐拉路相類似,只是由於起點會多貢獻一次,所以要使得異或值最大,我們可以遍歷每個點

假設以點i作爲起點,然後取最大值即可

【時間複雜度&&優化】
O(nlogn)

題目鏈接→HDU 5883 The Best Path

 Source Code

/*Sherlock and Watson and Adler*/
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<bitset>
#include<cmath>
#include<complex>
#include<string>
#include<algorithm>
#include<iostream>
#define eps 1e-9
#define LL long long
#define PI acos(-1.0)
#define bitnum(a) __builtin_popcount(a)
using namespace std;
const int N = 100005;
const int M = 100005;
const int inf = 1000000007;
const int mod = 1000000007;
int a[N],degree[N],s[N],vis[N];
int fun(int x)
{
    if(s[x]!=x)
        s[x]=fun(s[x]);
    return s[x];
}
int main()
{
    int t,n,m,i,u,v,k,c,ans,tmp;
    scanf("%d",&t);
    while(t--)
    {
        ans=c=k=0;
        memset(vis,0,sizeof(vis));
        memset(degree,0,sizeof(degree));
        scanf("%d%d",&n,&m);
        for(i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            s[i]=i;
        }
        for(i=0;i<m;i++)
        {
            scanf("%d%d",&u,&v);
            degree[u]++;
            degree[v]++;
            s[fun(u)]=fun(v);
        }
        for(i=1;i<=n;i++)
            vis[fun(i)]++;
        for(i=1;i<=n;i++)
        {
            if(vis[i]>1)
                k++;
            if(degree[i]%2)
                c++;
        }
        if(k>1||c!=0&&c!=2)
        {
            puts("Impossible");
            continue;
        }
        for(i=1;i<=n;i++)
            if(degree[i]%2)
            {
                if((degree[i]/2+1)%2)
                    ans^=a[i];
            }
            else
            {
                if(degree[i]/2%2)
                    ans^=a[i];
            }
        if(!c)
            for(tmp=ans,i=1;i<=n;i++)
                if(vis[fun(i)]>1)
                    ans=max(ans,tmp^a[i]);
        printf("%d\n",ans);
    }
    return 0;
}
菜鳥成長記
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章