洛谷 P1341 無序字母對
阿新 • • 發佈:2018-12-21
由於字串學的太少太差,這讓我看到字串就有一種天然的恐懼,不過這裡的字串實際上卻是一道圖論題,(字串需要好好加油鴨)
題意就是給你n個區分大小寫的無序字母對,然後讓你輸出一個n+1的字串要讓每個字母對都在這個字串裡面出現。
我們可以把每個字母對都想象成是一條邊,總共有n條邊。兩邊的字元分別是邊的兩個端點,我們就可以根據條件建出來一張圖。然後這個字串裡面也包含了n條邊,因此所有的邊都只出現了一次並且首尾相連,這就是尤拉路徑!
接下來我麼判定歐拉回路之前考慮這張圖是否連通,用並查集來維護一下端點就可以了。
然後我們考慮這裡的兩種情形,一個是構成歐拉回路,一個是未構成歐拉回路。我們遍歷一遍所有的點的度,對於前者所有的度數都為偶數,對於後者有且僅有兩個點的度數未奇數。那麼就很容易判定這個圖是否是尤拉圖了。
然後我們要去輸出這個字典序最小的路徑。這個地方有一個技巧。建圖的時候我們考慮用鄰接矩陣(鄰接矩陣不是沒有價值哦,我想到的是它可以快速判定兩點是否連通,連線的點序列滿足某種特定的順序)這裡就是我們存圖的時候必定是字典序的在前,所以我們每次去找的時候都能優先找到那個最小的字母,每次走完我們都取消掉那一條邊,最終的字串就是答案。這道題的演算法思想還是非常巧妙的,不失為一道好題。
#include<bits/stdc++.h> using namespace std; const int maxn=200; int n; char tmp[2],str[maxn]; int G[maxn][maxn],f[maxn],D[maxn]; void dfs(int x) { for(int i=1;i<maxn;i++) if(G[x][i]) G[x][i]=G[i][x]=0,dfs(i); str[n--]=x; } int find(int x){ if(f[x]==x) return f[x]; else return f[x]=find(f[x]); } int main() { for(int i=1;i<maxn;i++) f[i]=i; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%s",tmp); G[tmp[0]][tmp[1]]=G[tmp[1]][tmp[0]]=1; D[tmp[0]]++,D[tmp[1]]++; f[find(tmp[0])]=find(tmp[1]); } int ans=0,cnt=0,pos=0; for(int i=1;i<maxn;i++) if(f[i]==i&&D[i]) ++ans; if(ans!=1) { printf("No Solution\n");return 0; } for(int i=1;i<maxn;i++) { if(D[i]&1) { ++cnt; if(!pos) pos=i; } } if(cnt&&cnt!=2) { printf("No Solution\n");return 0;} if(!cnt) { for(int i=1;i<maxn;i++) { if(D[i]) { pos=i;break; } } } dfs(pos); puts(str); return 0; }