网上转载,有点偷懒
//求欧拉回路,注意欧拉图的性质 //构图的思想是以单词的首字母和末字母作为结点构图,将单词作为一条有向边 //(A)----acm------>(M)-----malform---->(M)------mouse----->(E) //1、第一步是要先对图的连通性进行判断,即去掉边的方向,看图是否连通 //我看了数据规模才26,我就偷懒写个Floyd水下算了 //2、第二步就是根据欧拉图的性质进行判断就可以了,判断存在欧拉道路或存在欧拉回路 //(1)有向图G为欧拉图(存在欧拉回路),当且仅当G的基图连通,且所有顶点的入度等于出度。 //(2)有向图G为半欧拉图(存在欧拉道路),当且仅当G的基图连通,且存在顶点u的入度比出度大1、v的入度比出度小1,其它所有顶点的入度等于出度。 #include<iostream> #include<vector> using namespace std; int indeg[26],outdeg[26],vis[26]; int G[26][26]; char word[1010]; vector<int> letter; int t,m; bool checkEulerPath() { int st,ed; st = ed = 0; bool circle = 1; for(int i = 0;i < letter.size();++i) { int x = letter[i]; if(indeg[x] - outdeg[x] == 1) { ++ed; circle = 0; } else if(outdeg[x] - indeg[x] == 1) { ++st; circle = 0; } else if(outdeg[x] != indeg[x]) return false; } if(circle) return true; if(st == 1 && ed == 1) return true; return false; } void Floyd() { for(int k = 0;k < 26;++k) for(int i = 0;i < 26;++i) for(int j = 0;j < 26;++j) if(G[i][k] && G[k][j]) G[i][j] = 1; } bool checkConnect() { Floyd(); for(int i = 0;i < letter.size();++i) for(int j = 0;j < letter.size();++j) { int x = letter[i]; int y = letter[j]; if(!G[x][y]) return false; } return true; } int main() { //freopen("in.txt","r",stdin); scanf("%d",&t); while(t--) { scanf("%d",&m); letter.clear(); memset(indeg,0,sizeof(indeg)); memset(outdeg,0,sizeof(outdeg)); memset(G,0,sizeof(G)); memset(vis,0,sizeof(vis)); while(m--) { scanf("%s",word); int last = word[strlen(word) - 1] - 'a'; int first = word[0] - 'a'; G[first][last] = G[last][first] = 1; indeg[last]++; outdeg[first]++; if(!vis[last]) { letter.push_back(last); vis[last] = 1; } if(!vis[first]) { letter.push_back(first); vis[first] = 1; } } if(checkConnect() && checkEulerPath()) printf("Ordering is possible.\n"); else printf("The door cannot be opened.\n"); } return 0; }