http://poj.org/problem?id=2337
题目大意:给出一组单词,如果两个单词,一个单词的头和另一个单词的尾相同,则可以相连,例如abce, efdg,可以相连,问这组单词能否排成一排,如果可以,求出字典序最小的那个。
思路:重点在建图。将单词的两个端点为顶点建有向边,用邻接表存储,用头插法建邻接表时,首先应对输入的字符串从大到小排序,这样才能保证按字典序输出。
首先判断图的连通性,然后判断是否欧拉路或欧拉通路。若是欧拉路,以出度大入度为1的点为起点,若是欧拉回路则以字典序最小的点为起点进行dfs。
#include <stdio.h> #include <string.h> #include <algorithm> #include <stack> #include <vector> #define LL long long #define _LL __int64 using namespace std; struct node { int u,v; int next; char str[22]; int vis; bool operator < (const struct node &tmp)const { if(strcmp(str,tmp.str) > 0) return true; return false; } }s[1010]; int in[1010],out[1010]; //保存每个点的出入度 int cnt;//顶点个数 int ok[26];//ok[i] = 1 : i+‘a‘是顶点 int set[26]; int start,end;//记录欧拉路的起点与终点 int head[26]; char ans[1010][22];//保存输出结果 int c; void init() { memset(in,0,sizeof(in)); memset(out,0,sizeof(out)); memset(ok,0,sizeof(ok)); cnt = 0; for(int i = 0; i < 26; i++) set[i] = i; memset(head,-1,sizeof(head)); c = 0; } int find(int x) { if(set[x] != x) set[x] = find(set[x]); return set[x]; } //并查集判断是否图是否连通 bool check() { int flag = 1; for(int i = 0; i < 26; i++) { if(!ok[i]) continue; for(int j = i+1; j < 26; j++) { if(!ok[j]) continue; if(find(i) != find(j)) { flag = 0; break; } } if(!flag) break; } if(flag) return true; return false; } //判断是欧拉路还是欧拉回路 int judge() { int c1 = 0,c2 = 0,c3 = 0; for(int i = 0; i < 26; i++) { if(ok[i]) { if(in[i] == out[i]) c3++; else if(in[i]-out[i] == 1) { end = i; c1++; } else if(out[i]-in[i] == 1) { start = i; c2++; } } } if(c3 == cnt) return 2; //欧拉回路 else if(c1 == 1 && c2 == 1 && c3 == cnt-2) //欧拉路 return 1; else return 0; } //dfs寻找欧拉路或欧拉回路,注意输出是逆序输出 void dfs(int u) { for(int i = head[u]; i != -1; i = s[i].next) { if(!s[i].vis) { s[i].vis = 1; dfs(s[i].v); strcpy(ans[c++],s[i].str); } } } int main() { int test,n,u,v; scanf("%d",&test); while(test--) { init(); scanf("%d",&n); for(int i = 0; i < n; i++) { scanf("%s",s[i].str); s[i].vis = 0; } sort(s,s+n); //对边从大到小排序 for(int i = 0; i < n; i++) { int len = strlen(s[i].str); u = s[i].str[0]-‘a‘; v = s[i].str[len-1]-‘a‘; if(!ok[u]) { ok[u] = 1; cnt++; } if(!ok[v]) { ok[v] = 1; cnt++; } //头插法建边 s[i].u = u; s[i].v = v; s[i].next = head[u]; head[u] = i; out[u]++; in[v]++; int uu = find(u); int vv = find(v); if(uu != vv) set[uu] = vv; } if(!check()) { printf("***\n"); continue; } int res = judge(); if(!res) { printf("***\n"); continue; } else if(res == 1) //欧拉路 { dfs(start); } else //欧拉回路 { for(int i = 0; i < 26; i++) { if(ok[i]) { start = i; break; } } dfs(start); } printf("%s",ans[c-1]); for(int i = c-2; i >= 0; i--) printf(".%s",ans[i]); printf("\n"); } return 0; }
poj 2337 Catenyms(欧拉路+字典序+打印路径),布布扣,bubuko.com
poj 2337 Catenyms(欧拉路+字典序+打印路径)
原文:http://blog.csdn.net/u013081425/article/details/24044627