1. 程式人生 > >洛谷 P1341 無序字母對

洛谷 P1341 無序字母對

由於字串學的太少太差,這讓我看到字串就有一種天然的恐懼,不過這裡的字串實際上卻是一道圖論題,(字串需要好好加油鴨)
題意就是給你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;
}