标签:fir 组成 efault 英文 col row ssi turn ibm
来自 ICPC CERC 1999/2000,有改动。
有 N 个盘子,每个盘子上写着一个仅由小写字母组成的英文单词。你需要给这些盘子安排一个合适的顺序,使得相邻两个盘子中,前一个盘子上单词的末字母等于后一个盘子上单词的首字母。请你编写一个程序,判断是否能达到这一要求。如果能,请给出一个合适的顺序。
多组数据。第一行给出数据组数T,每组数据第一行给出盘子数量 N,接下去 N 行给出小写字母字符串,一种字符串可能出现多次。
若存在一组合法解输出Ordering is possible.
,否则输出The door cannot be opened.
。
3
2
acm
ibm
3
acm
malform
mouse
2
ok
ok
The door cannot be opened.
Ordering is possible.
The door cannot be opened.
1≤N≤10^5,∣S∣≤1000
It‘s a good problem,这是一道判断有无欧拉路的题,欧拉路及欧拉回路的题码量不大,下面我来简述一下这道题
首先,我们看到首尾相连,可以想到向首到尾连一条边
即若单词为handsomeboy,则从h连向y即可,这一条路是什么意思呢?这说明选一个单词,前一个单词要么不选要么就选一首为结尾的单词,尾亦然
连完边后,题目就变成了求原图中是否有欧拉路径
欧拉回路亦可,例如:ab,ba,这就是一个欧拉回路,但是由于一条边可以不走,所以也可行
判断是否为欧拉路径的方法: 1.原图中只有一个入度比出度多一的点和一个入度比出度少一的点 2.原图是连通图
然后就可以AC了
上代码
#include<iostream> #include<cstring> #include<algorithm> #include<cstdio> #include<cmath> #define rep(i,a,b) for(int i=a;i<=b;i++) using namespace std; int in[30],out[30],t,n,sum,tot=-1,fir[30],nxt[200005],to[200005],firs[30]; char a[100500]; bool check(){ int zlk=0,wyx=0; rep(i,0,25){ if(abs(in[i]-out[i])>1) return 0; if(in[i]-out[i]==1) ++zlk; else if(out[i]-in[i]==1) ++wyx; } if(zlk==1 && wyx==1) return 1; if(!zlk && !wyx) return 1; return 0; } void ade(int u,int v){ to[++tot]=v; nxt[tot]=fir[u]; fir[u]=tot; } void euler(int x){ while(fir[x]){ int k=fir[x]; fir[x]=nxt[k]; euler(to[k]); ++sum; } } int main(){ //freopen("1.txt","r",stdin); // freopen("1.out","w",stdout); scanf("%d",&t); while(t--){ scanf("%d",&n); memset(fir,0,sizeof(fir)); tot=0; memset(in,0,sizeof(in)); memset(out,0,sizeof(out)); rep(i,1,n){ scanf("%s",a); in[a[strlen(a)-1]-‘a‘]++; out[a[0]-‘a‘]++; ade(a[0]-‘a‘,a[strlen(a)-1]-‘a‘); } rep(i,0,25) firs[i]=fir[i]; if(!check()) puts("The door cannot be opened."); else{ rep(i,0,25){ sum=0; if(fir[i]!=-1){ euler(i); if(sum==n){ sum=-1; puts("Ordering is possible."); break; } } rep(j,0,25) fir[j]=firs[j]; } if(sum!=-1) puts("The door cannot be opened."); } } return 0; }
标签:fir 组成 efault 英文 col row ssi turn ibm
原文地址:https://www.cnblogs.com/handsome-zlk/p/10186747.html