POJ2337 歐拉回路

題意:給你n個由小寫字母組成的單詞,要求將這n個單詞連接起來,使得前一個單詞的最後一個字母和後一個單詞的第一個字母相容,輸出字典序最小的解

思路:不難發現此題可以轉化爲歐拉路徑問題,把每個字符串的第一個字母當作起點,最後一個字母當作終點,連一條有向邊,求此圖字典序最小的歐拉路徑。

對於有向圖來說,存在一條歐拉路徑的充要條件爲此圖聯通並且要麼對於每個頂點都有出度等於入度,要麼有且僅有一個頂點出度比入度少1,有且僅有一個頂點入度比出度少1,其餘頂點出度等於入度。

對於聯通性的判斷來說,直接用dfs即可,只要能把所有的邊都遍歷到,此圖就是聯通的。當然也可以用並查集判斷聯通。

對於字典序最小的要求,只需把給定的所有字符串排序,按照字典序從小到大的順序加邊即可。

代碼如下

#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
#include<vector>
using namespace std;
string s[1005];
int in[26],out[26];
struct node
{
    int y,id,flag;
    node(int ty,int tid,int tflag):y(ty),id(tid),flag(tflag){}
    node(){}
};
vector<node> g[26];
int ans[1005];
int cnt=0;
void dfs(int now)
{
    for(int i=0;i<g[now].size();i++)
    {
        if(!g[now][i].flag)
        {
            g[now][i].flag=1;
            dfs(g[now][i].y);
            ans[++cnt]=g[now][i].id;
        }
    }
}
int main()
{
    ios_base::sync_with_stdio(0);
    int T;
    cin>>T;
    while(T--)
    {
        for(int i=0;i<26;i++)
            g[i].clear();
        memset(in,0,sizeof in);
        memset(out,0,sizeof out);
        int n;
        cin>>n;
        for(int i=1;i<=n;i++)
            cin>>s[i];
        sort(s+1,s+1+n);
        int st=100;
        for(int i=1;i<=n;i++)
        {
            int a=s[i][0]-'a';
            int b=s[i][s[i].size()-1]-'a';
            st=min(st,a);
            g[a].push_back(node(b,i,0));
            out[a]++;in[b]++;
        }
        int d1=0,d2=0;
        for(int i=0;i<26;i++)
        {
            if(out[i]-in[i]==1)
            {
                d1++;
                st=i;
            }
            else if(in[i]-out[i]==1)
            {
                d2++;
            }
            else if(out[i]-in[i])
            {
                d1=100;
            }
        }
        if(!(d1==1&&d2==1||d1==0&&d2==0))
        {
            printf("***\n");
            continue;
        }
        cnt=0;
        dfs(st);
        if(cnt!=n)
        {
            printf("***\n");
            continue;
        }
        for(int i=cnt;i>=1;i--)
        {
            cout<<s[ans[i]];
            if(i==1) cout<<endl;
            else cout<<".";
        }
    }
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章