傳送門c++
Some of the secret doors contain a very interesting word puzzle. The team of archaeologists has to solve it to open that doors. Because there is no other way to open the doors, the puzzle is very important for us.app
There is a large number of magnetic plates on every door. Every plate has one word written on it. The plates must be arranged into a sequence in such a way that every word begins with the same letter as the previous word ends. For example, the word acm'' can be followed by the word motorola''. Your task is to write a computer program that will read the list of words and determine whether it is possible to arrange all of the plates in a sequence (according to the given rule) and consequently to open the door.ui
The input consists of T test cases. The number of them (T, equal to about 500) is given on the first line of the input file. Each test case begins with a line containing a single integer number N that indicates the number of plates (1 <= N <= 100000). Then exactly Nlines follow, each containing a single word. Each word contains at least two and at most 1000 lowercase characters, that means only letters 'a
' through 'z
' will appear in the word. The same word may appear several times in the list.this
Your program has to determine whether it is possible to arrange all the plates in a sequence such that the first letter of each word is equal to the last letter of the previous word. All the plates from the list must be used, each exactly once. The words mentioned several times must be used that number of times.spa
If there exists such an ordering of plates, your program should print the sentence "Ordering is possible.
". Otherwise, output the sentence "The door cannot be opened.
".rest
Sample input: 3 2 acm ibm 3 acm malform mouse 2 ok ok Sample output: The door cannot be opened. Ordering is possible. The door cannot be opened.
-----------------------------------------------------
題目要求將全部單詞排列成such that the first letter of each word is equal to the last letter of the previous word。這道題是典型的歐拉路徑問題,這種問題分析起來仍是有必定難度的。
咱們考慮如何建圖
將26個字母當作節點,將每一個單詞當作從其首字母向尾字母的有向邊。
問題轉換成判斷有向圖中是否存在一條歐拉路徑。
-----------------------------------------------------
Solution
一個有向圖存在歐拉路徑的必要條件是:
每一個節點的出度都等於入度
或
存在一個節點s,其入度比出度少1,存在一個節點t,其出度比入度多1
在前一種狀況下若圖中存在歐拉路徑,那麼起點和終點必然是同一點,並且任意出度不爲0的節點均可做爲起點,
在後一種狀況下若圖中存在歐拉路徑,那s必然是起點,t必然是終點。
-----------------------------------------------------
但上述條件僅僅是必要條件,除此以外還要求圖「連通」,
即要求從前面肯定的起點出發能夠走完全部邊(這好像是廢話)
其實前面的必要條件僅能快速判斷出歐拉路徑不存在的狀況,
對於歐拉路徑存在的狀況仍然要經過遍歷圖中的邊來確認。
------------------------------------------------------
下面考慮如何遍歷有向圖(可能存在重邊、自環)中的邊。
若是用vector<int> g[N存圖的話不是很方便,而鏈式前向星是比較方便的
請特別注意下面代碼中加粗的三行,並請考慮若是將那三行改爲下面兩種寫法
有什麼問題
void dfs(int u){ for(; ~head[u]; head[u]=E[head[u]].nt){ int &v=E[head[u]].to; dfs(v); } }
void dfs(int u){ for(; ~head[u];){ int &v=E[head[u]].to; head[u]=E[head[u]].nt; dfs(v); } }
----------------------------------------------------------
Code
#include <bits/stdc++.h> using namespace std; char s[1005]; int in[26], out[26]; const int M(1e5+5); struct edge{ int to, nt; }E[M]; int head[26]; void dfs(int u){ for(; ~head[u];){ int v=E[head[u]].to; //this edge has been used head[u]=E[head[u]].nt; dfs(v); } } bool solve(int n){ bool flag=true; for(int i=0; i<26; i++)if(in[i]!=out[i]){flag=false; break;} if(flag){ for(int i=0; i<26; i++) if(out[i]){dfs(i); break;} for(int i=0; i<26; i++) if(~head[i]) return 0; return 1; } int s=-1, t=-1; for(int i=0; i<26; i++){ if(in[i]!=out[i]){ if(abs(in[i]-out[i])!=1) return 0; if(in[i]>out[i]){ if(~t) return 0; t=i; } else if(in[i]<out[i]){ if(~s) return 0; s=i; } } } if(~s&&~t){ dfs(s); for(int i=0; i<26; i++) if(~head[i]) return 0; return 1; } return 0; } int main(){ int T; scanf("%d", &T); for(int n; T--;){ scanf("%d", &n); memset(in, 0, sizeof(in)); memset(out, 0, sizeof(out)); memset(head, -1, sizeof(head)); for(int len, u, v, id=0, _=n; _--;){ scanf("%s", s); len=strlen(s); u=s[0]-'a', v=s[len-1]-'a'; out[u]++, in[v]++; E[id]={v, head[u]}, head[u]=id++; } puts(solve(n)?"Ordering is possible.":"The door cannot be opened."); } }