单词拼接
时间限制:
3000 ms | 内存限制:
65535 KB
难度:
5
-
描述
-
给你一些单词,请你判断能否把它们首尾串起来串成一串。
前一个单词的结尾应该与下一个单词的道字母相同。
如
aloha
dog
arachnid
gopher
tiger
rat
可以拼接成:aloha.arachnid.dog.gopher.rat.tiger
-
输入
-
第一行是一个整数N(0<N<20),表示测试数据的组数
每组测试数据的第一行是一个整数M,表示该组测试数据中有M(2<M<1000)个互不相同的单词,随后的M行,每行是一个长度不超过30的单词,单词全部由小写字母组成。
输出
-
如果存在拼接方案,请输出所有拼接方案中字典序最小的方案。(两个单词之间输出一个英文句号".")
如果不存在拼接方案,则输出
***
样例输入
-
2 6 aloha arachnid dog gopher rat tiger 3 oak maple elm
样例输出
-
aloha.arachnid.dog.gopher.rat.tiger ***
来源
Waterloo local 2003.01.25 /POJ
我先在网上找了并查集的:
代码1:
#include <iostream> #include <cstdio> #include <cstring> using namespace std; struct adjLink { int v, nxt; char word[30]; }adj[2000]; int adjN; void insert(int beg, int end, char word[30])//类似于hash,第一个节点数据域不存值只有指针部分有效。链表中单词按字典序排列。 { int i; for (i = beg; adj[i].nxt != -1; i = adj[i].nxt) if (strcmp(adj[adj[i].nxt].word, word) >= 0) break; adj[adjN].v = end; strcpy(adj[adjN].word, word); adj[adjN].nxt = adj[i].nxt; adj[i].nxt = adjN++; } int vis[30], count; void dfs(int cur)//检查连通性 { vis[cur] = 1; count++; for (int i = adj[cur].nxt; i != -1; i = adj[i].nxt) if (!vis[adj[i].v]) dfs(adj[i].v); } int path[2000], npath; void euler(int cur, int edgeN) //cur当前到达的节点 edgeN上一被选择的边,即上一个节点通过edgeN到达的cur { int i; while(adj[cur].nxt != -1) { i=adj[cur].nxt; adj[cur].nxt=adj[i].nxt; euler(adj[i].v,i); } path[npath++] = edgeN; //后序记录 输出的时候为了保证字典序,需逆向输出 } void go() { int n, i; scanf("%d", &n); for (i = 0; i < 26; i++) adj[i].nxt = -1; adjN = i; int flag[30], tot = 0, cnt[30]; memset(flag, 0, sizeof(flag)); memset(cnt, 0, sizeof(cnt)); for (i = 0; i < n; i++) { char word[30]; scanf("%s", word); int a = word[0] - 'a', b = word[strlen(word) - 1] - 'a'; // int len = strlen(word); // word[len] = '.'; // word[len + 1] = 0; insert(a, b, word); cnt[b]--; cnt[a]++; if (!flag[a]) flag[a] = 1, tot++; if (!flag[b]) flag[b] = 1, tot++; } for (i = 0; i < 26; i++) { memset(vis, 0, sizeof(vis)); count = 0; dfs(i); if (count == tot) break; } if (i == 26) { printf("***\n"); return ; } int flagIn = 0, flagOut = 0, flagNo = 0, site; for (i = 0; i < 26; i++) if (cnt[i] == -1) flagIn++; else if (cnt[i] == 1) flagOut++, site = i; else if (cnt[i]) flagNo = 1; if (flagNo || flagIn > 1 || flagOut > 1 || flagIn != flagOut)//根据欧拉通路的充要条件 将不符合的先排除掉 { printf("***\n"); return ; } npath = 0; if (flagOut == 0) { for (i = 0; i < 26; i++) if (adj[i].nxt != -1) { site = i; break; } } euler(site, -1); //因为直接从site出发,所以第二个参数用-1代替,输出的时候要忽略掉. for (i = npath - 2; i > 0; i--) printf("%s.", adj[path[i]].word); // int len = strlen(adj[path[0]].word); // adj[path[0]].word[len-1] = 0;//多一个.,所以len大1 printf("%s\n", adj[path[0]].word); } int main() { int T; scanf("%d", &T); while (T--) go(); return 0; }
代码2:#include<stdio.h> #include<string.h> # define N 1000 # define X 26 int P[X+1],path[N],IN[X],OUT[X],EE[X]; char T[N][31],S[2][N],*tt[N],VIS[N],*W; void Link(int P[],int x,int y); int find(int P[],int x); void Qsort(int L,int R);//快速排序升序 void change(char *a,char *b) { //交换函数 char c=*a; *a=*b; *b=c; } int DFS(int U,int m,int C); int main(){ int m,n,i,j,k,L=-1,ca,cb,cc,start; //freopen("ttt.txt","r",stdin); scanf("%d",&n); while(n--){ for(i=0;i<X;i++) P[i]=i; scanf("%d",&m); for(i=0;i<m;i++,L=-1) { tt[i]=T[i]; scanf("%s",&T[i]); while(T[i][++L]); S[0][i]=T[i][0]-'a'; S[1][i]=T[i][L-1]-'a'; Link(P,S[0][i],S[1][i]); IN[S[1][i]]++; OUT[S[0][i]]++; EE[S[0][i]]=EE[S[1][i]]=1; VIS[i]=0; } Qsort(0,m-1); for(ca=cb=cc=start=i=0;i<X;i++) { if(EE[i]&&P[i]==i){ ca++; if(ca>1)break; } if(IN[i]==OUT[i])continue; else { if(IN[i]==OUT[i]+1)cb++; else if(IN[i]==OUT[i]-1) { cc++; start=i; } else break; } } if((cb==cc||cb<2)&&i==X&&DFS(start,m,0)) { printf("%s",tt[path[0]]); for(i=1;i<m;i++) printf(".%s",tt[path[i]]); printf("\n"); } else printf("***\n"); for(i=0;i<X;i++) IN[i]=EE[i]=OUT[i]=0; } return 0; } int find(int P[],int x) { while(x!=P[x])x=P[x]; return x; } void Link(int P[],int x,int y) { int fy=find(P,y),fx=find(P,x); if(fy!=fx) P[fy]=fx; } void Qsort(int L,int R)//快速排序 升序 { int i=L,j=R; char *temp=tt[L]; if(L>R) return; while(i!=j) //当数组左右两边没相遇 { while(strcmp(tt[j],temp)>=0&&i<j)j--; //从右向左找 改为while(A[j]<=T&&i<j) while(strcmp(tt[i],temp)<=0&&i<j)i++; //从左向右找 改为while(A[i]>=T&&i<j) 这两处 改完即为降序 if(i<j){ change(&S[0][i],&S[0][j]); change(&S[1][i],&S[1][j]); W=tt[i];tt[i]=tt[j];tt[j]=W; } //交换两数 } if(L!=i){ change(&S[0][i],&S[0][L]); change(&S[1][i],&S[1][L]); W=tt[i];tt[i]=tt[L];tt[L]=W; } //基准数归位 Qsort(L,i-1); //递归左 Qsort(i+1,R); //递归右 } int DFS(int U,int m,int C) { int F=0,i; if(C==m)return 1; for(i=0;i<m;i++) { if(!VIS[i]&&S[0][i]==U) { VIS[i]=1; path[C]=i; F=DFS(S[1][i],m,C+1); VIS[i]=0; if(F)return 1; } } return 0; }
-
第一行是一个整数N(0<N<20),表示测试数据的组数