Uva10129(DFS搜索+聯通集)

題目地址:

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&category=838&problem=1070&mosmsg=Submission+received+with+ID+21459508

題目分析:

n個單詞形成序列,能夠使每一個單詞的第一個字母和上一個單詞的最後一個字母相同,即是否形成歐拉通路,所以先以每個單詞的首、尾形成點,連成有向邊構圖。但需要注意的是:只能存在一個歐拉通路(即一個聯通集)!這可以通過遞歸完一次dfs搜索後,再一次掃描所有單詞,判斷是否還存在沒有訪問到的邊。

代碼如下:

#include <bits/stdc++.h>
using namespace std;

const int maxn = 100;

int T, n, G[maxn][maxn], c[maxn], in[maxn], out[maxn];
int vis[maxn];      //判斷邊的關係 
char s[1010];

void read_word(){
    for(int i = 0;i < n;i++){
        scanf("%s",s);
        int len = strlen(s);
        int r = s[0] - 'a';     //首字母
        int t = s[len - 1] - 'a';       //尾字母 
        G[r][t] = 1;        //記錄邊的關係 
        out[r]++;in[t]++;
        vis[r] = vis[t] = 0;        //設置爲未訪問狀態 
    }
}


void dfs(int u){
    vis[u] = 1;     //設置爲訪問狀態 
    for(int v = 0; v < 26;v++)
        if(!vis[v] && G[u][v]) dfs(v);        //遞歸尋找所有u的子孫
}

int main(void){
    //freopen("data.out","w",stdout);
    scanf("%d",&T);
    while(T--){
        memset(vis,-1,sizeof(vis)); 
        memset(G,0,sizeof(G));
        memset(in,0,sizeof(in));
        memset(out,0,sizeof(out));
        scanf("%d",&n);
        
        read_word();
        
        int p = 0, begin = 0, tail = 0, cnt = 0;
        
        int flag = 0;
        for(int i = 0;i < 26;i++){
            if(out[i] == in[i]){    //中間節點,則跳過下面的步驟 
                continue;
            }
            if(out[i] == in[i] + 1){    //是起始點 
                begin++;p = i;
            } else if(in[i] == out[i] + 1)      //終止點 
                tail++;
            else
                cnt++;      //入度不等於出度,並且不爲起始點或者終止點 
        }
        
        if(cnt > 0){        //如果個別節點 
            cout<<"The door cannot be opened.\n";
            continue;
        }   
        
        if(begin == 1 && tail == 1 || begin == 0 && tail == 0)  //有一個奇度起點與終點,或者全部爲偶數度頂點 
            flag = 1;
        else 
            flag = 0;
        
        
        dfs(p);        //dfs返回後掃描完了一個聯通集
        //掃描所有字母,判斷只有一個聯通集
        for(int i = 0;i < 26;i++){
            if(!vis[i]) flag = 0;       //如果還有未訪問的聯通集 
        }   
        
        if(flag) cout<<"Ordering is possible.\n";
        else cout<<"The door cannot be opened.\n";
    }
    return 0;
}
發佈了102 篇原創文章 · 獲贊 4 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章