本文版權歸ljh2000和博客園共有,歡迎轉載,但須保留此聲明,並給出原文鏈接,謝謝合作。
本文作者:ljh2000
作者博客:http://www.cnblogs.com/ljh2000-jump/
轉載請注明出處,侵權必究,保留最終解釋權!
Description
Input
第一行包含兩個整數N和 M, 表示該無向圖中點的數目與邊的數目。 接下來M 行描述 M 條邊,每行三個整數Si,Ti ,Di,表示 Si 與Ti之間存在 一條權值為 Di的無向邊。 圖中可能有重邊或自環。
Output
僅包含一個整數,表示最大的XOR和(十進制結果),注意輸出后加換行回車。
Sample Input
1 2 2
1 3 2
2 4 1
2 5 1
4 5 3
5 3 4
4 3 2
Sample Output
HINT
正解:dfs+線性基
解題報告:
繼續刷線性基...
這道題要求從1到n的最大xor和路徑,存在重邊,允許經過重復點、重復邊。那么在圖上作圖嘗試之后就會發現,路徑一定是由許多的環和一條從1到n的路徑組成。容易發現,來回走是沒有任何意義的,因為來回走意味着抵消。考慮這道題求得是路徑xor和最大,所以必然我們要想辦法處理環的情況。我的做法是任意地先找出一條從1到n的路徑,把這條路徑上的xor和作為ans初值(先不管為什么可行),然后我們的任務就變成了求若干個環與這個ans初值所能組合成的xor最大值。顯然,我們需要預處理出圖上所有的環,並處理出所有環的環上xor值,這當然是dfs尋找,到n的路徑的時候順便求一下就可以了。
當我們得到了若干個環的xor值之后,因為是要求xor最大值,我們就可以構出這所有xor值的線性基。構出之后,再用ans在線性基上取max就可以了。
現在我們來討論上述做法的可行性。
第一種情況:我們對最終答案產生貢獻的某個環離1到n的主路徑很遠,這樣的話,因為至少可以保證1可以到達這個環,那么我們可以走到這個環之后繞環一周之后原路返回,這樣從1走到環的路上這一段被重復經過所以無效,但是環上的xor值被我們得到了,所以我們並不關心這個環和主路徑的關系,我們只關心環的權值。
第二種情況:我們任意選取的到n的路徑是否能保證最優性。假設存在一條更優的路徑從1到n,那么這條路徑與我們原來的路徑構成了一個環,也就會被納入線性基中,也會被計算貢獻,假如這個環會被經過,那么最后的情況相當於是走了兩遍原來選取的路徑,抵消之后走了一次這個最優路徑,所以我們無論選取的是哪條路徑作為ans初值,都可以通過與更優情況構成環,然后得到一樣的結果。這一證明可以拓展到路徑上的任意點的路徑選取。
這樣我們就可以完美解決了。我第一次WA了一發,因為我沒有考慮到ans初值不為0,在線性基上取到xor的max的時候,不能單純以ans這一位是否為0來決定是否異或上基的這一位,必須要看異或之后取一個max做一個判斷才行。
1 //It is made by jump~ 2 #include <iostream> 3 #include <cstdlib> 4 #include <cstring> 5 #include <cstdio> 6 #include <cmath> 7 #include <algorithm> 8 #include <ctime> 9 #include <vector> 10 #include <queue> 11 #include <map> 12 #include <set> 13 using namespace std; 14 typedef long long LL; 15 const int MAXN = 50011; 16 const int MAXM = 200011; 17 int n,m,ecnt; 18 int first[MAXN],next[MAXM],to[MAXM]; 19 LL w[MAXM],dx[MAXN]; 20 bool vis[MAXN]; 21 int cnt; 22 LL circle[MAXM],ans;//經過每個環可獲得的的權值 23 LL p[63]; 24 25 inline int getint(){int w=0,q=0;char c=getchar();while((c<'0'||c>'9')&&c!='-')c=getchar();if(c=='-')q=1,c=getchar();while (c>='0' && c<='9') w=w*10+c-'0', c=getchar(); return q ? -w : w;} 26 inline LL getlong(){LL w=0,q=0;char c=getchar();while((c<'0' || c>'9')&&c!='-')c=getchar();if(c=='-') q=1,c=getchar();while (c>='0' && c<='9') w=w*10+c-'0', c=getchar(); return q ? -w : w;} 27 28 inline void dfs(int x){ 29 vis[x]=1; 30 for(int i=first[x];i;i=next[i]) { 31 int v=to[i]; 32 if(!vis[v]) dx[v]=dx[x]^w[i],dfs(v); 33 else circle[++cnt]=dx[v]^dx[x]^w[i]; 34 } 35 } 36 37 inline void work(){ 38 n=getint(); m=getint(); int x,y; LL z; 39 for(int i=1;i<=m;i++) { 40 x=getint(); y=getint(); z=getlong(); 41 next[++ecnt]=first[x]; first[x]=ecnt; to[ecnt]=y; w[ecnt]=z; 42 next[++ecnt]=first[y]; first[y]=ecnt; to[ecnt]=x; w[ecnt]=z; 43 } 44 dfs(1); 45 ans=dx[n];//任取一條從1到n的路徑,並得到其xor和 46 for(int i=1;i<=cnt;i++)//構造線性基 47 for(int j=62;j>=0;j--) { 48 if(!(circle[i]>>j)) continue; 49 if(!p[j]) { p[j]=circle[i]; break; } 50 circle[i]^=p[j]; 51 } 52 //for(int i=62;i>=0;i--) if(!(ans>>i)) ans^=p[i]; 53 //ans有初值,不能直接根據這一位是否為0來判斷是否更大,max更為穩妥 54 for(int i=62;i>=0;i--) if((ans^p[i])>ans) ans=ans^p[i];//從線性基中得到最大值 55 printf("%lld",ans); 56 } 57 58 int main() 59 { 60 work(); 61 return 0; 62 }