UVA 10129 Play on Words(歐拉回路)

Question:題目詳情(http://vjudge.net/contest/133965#problem/C)
題目大意:有很多單詞,要你把他們排列成一個單詞的末尾爲下一個單詞的首字母,問這麼排列是否可行
解題思路:根據題意建立一個無向圖(一個單詞的首尾字母關係),判斷圖中是否存在歐拉回路,判斷歐拉路徑的方法兩個因素:1。圖必須連通(並查集,dfs可執行),2。出入度數必須滿足每個節點的入度和出度相等(有可能除去除開始,結尾),開始節點(入度+1==出度),末尾節點(入度=出度+1),開始末尾節點可能存在(有可能又回到了初始節點),存在也只能各存在一個

//並查集解法
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
using namespace std;
const int maxn=30;
char s[1005];
int fa[maxn],g[maxn][maxn],in[maxn],out[maxn],flag;
int findx(int x){  //找其父節點
    if(fa[x]!=x)
        return fa[x]=findx(fa[x]);
    else return x;
}
void Union(int x,int y){   //將兩個節點關聯
    int t1=findx(x),t2=findx(y);
    if(t1!=t2)
        fa[t1]=t2;
}
bool judge(){   //判斷是否存在歐拉路徑:每個節點的入度和出度相等(有可能除去除開始,結尾),開始節點(入度+1==出度),末尾節點(入度=出度+1),開始末尾節點可能存在(有可能又回到了初始節點)
    bool Star=false ,End=false;
    for(int i=0;i<maxn;i++){
        if(in[i]!=out[i]){
            if(in[i]+1==out[i]&&!Star)
                Star=true;
            else if(in[i]==out[i]+1&&!End)
                End=true;
            else return false ;
        }
    }
    return true;
}
int main(){
    int T;
    cin>>T;
    while(T--){
        int n;
        scanf("%d",&n);
        memset(g,0,sizeof(g));
        memset(in,0,sizeof(in));
        memset(out,0,sizeof(out));
        for(int i=0;i<maxn;i++)
            fa[i]=i;
        for(int i=0;i<n;i++){
            scanf("%s",s);
            int u=s[0]-'a',v=s[strlen(s)-1]-'a';
            in[v]++;   //每個節點的入度
            out[u]++;    //每個節點的出度
            Union(u,v);
        }
        if(judge()){
            flag=0;
            for(int i=0;i<maxn;i++){
                if(in[i]+out[i])
                    if(fa[i]==i)
                       flag++;   
            }
            if(flag>1)   //如果只有一個父節點,則說明給出的圖是連通的 
                printf("The door cannot be opened.\n");
            else printf("Ordering is possible.\n");
        }
        else printf("The door cannot be opened.\n");
    }
    return 0;
}
//DFS
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
using namespace std;
#define maxn 30
char s[1005];
int g[maxn][maxn],vis[maxn],in[maxn],out[maxn],star;
void dfs(int);
bool okdfs();
bool judge();
int main(){
    int T;
    cin>>T;
    while(T--){
        int n;
        cin>>n;
        memset(vis,0,sizeof(vis));
        memset(g,0,sizeof(g));
        memset(in,0,sizeof(in));
        memset(out,0,sizeof(out));
        for(int i=0;i<n;i++){
            cin>>s;
            int u=s[0]-'a',v=s[strlen(s)-1]-'a';
            in[v]++;
            out[u]++;
            g[u][v]++;  //根據一個單詞的首字母和尾字母關係,建圖
            g[v][u]++;
            star=u;
        }
        dfs(star);   //從任意節點開始訪問節點
        if(judge()&&okdfs())
            printf("Ordering is possible.\n");
        else printf("The door cannot be opened.\n");
    }
    return 0;
}
void dfs(int u)   //用dfs訪問所有的節點
{
    vis[u]=1;
    for(int i=0;i<maxn;i++){
        if(g[u][i]>0){
            g[u][i]--;
            g[i][u]--;
            dfs(i);
        }
    }
}
bool okdfs()  //判斷是否節點是否都被訪問到了
{
    for(int i=0;i<maxn;i++){
        if(in[i]+out[i])    //有些點可能給出的數據沒有(因爲有26個字母)
            if(!vis[i])
                return false;
    }
    return true;
}
bool judge()   //判斷是否度數滿足歐拉路徑
{
    bool Star=false,End=false;
    for(int i=0;i<maxn;i++){
        if(in[i]!=out[i]){
            if(in[i]+1==out[i]&&!Star)  //只有一個起始節點
               Star=true;
        else if(in[i]==out[i]+1&&!End) //只有一個末尾節點
            End=true;
        else return false;
        }
    }
    return true;
}

體會:並查集很簡單,但自己的dfs很容易出問題,還得多練歐拉回路,dfs

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