描述
程序员常常需要给变量命名、给函数命名、给项目命名、给团队命名…… 好的名字可以大大提高程序员的主观能动性,所以很多程序员在起名时都会陷入纠结和烦恼。
小Hi希望给新的项目起个完美的名字。首先小Hi给出了新项目的N个长度相等(均为L)的关键字,他希望能找到一个完美名字:这个名字的长度恰好为N+L-1,并且其中N个长度为L的子串恰好是给定的N个关键字。
例如对于关键字cat、ate、tea有完美的名字:catea。
给定N个长度相等的关键字,请你帮小Hi找到一个完美的名字。
输入
第一行包含一个整数N。
以下N行每行包含一个长度为L的关键字。
对于30%的数据,1 ≤ N ≤ 10
对于100%的数据,1 ≤ N ≤ 50000,1 ≤ L ≤ 10,关键字只包含小写字母。
输出
如果存在完美的名字,你可以输出任意一个。如果不存在,输出NO。
样例输入
3 ate cat tea
样例输出
catea
模型:成语接龙。
以前做过类似的题,有所灵感,知道怎么建图。
- 如单词abcd,我们加一条有向边abc->bcd,
- 那么ate,cat,tea,就是有边at->te, ca->at, te->ea。那么一笔画就是ca->at->te-ea,得到catea。
做完的感触。
- 真的是wa了好久,主要是没有考虑只有一个字母长度的情况(毕竟代码里有‘L-2’这个东西)
- 注意‘NO’的情况,如果不能连通;如果连通了但是不满足欧拉路的条件(无奇点,或一个起点一个终点)
- 逆序输出。
#include<cstdio> #include<cstdlib> #include<iostream> #include<cstring> #include<algorithm> #include<cmath> #include<map> using namespace std; const int maxn=200010; map<string,int>mp; map<int,string>name; char c[20];string s1,s2; int Laxt[maxn],Next[maxn],To[maxn],cnt,tot,num;//边,点,路 int id[maxn],od[maxn],used[maxn],path[maxn]; int a[maxn],b[maxn];//起点; void add(int u,int v) { Next[++cnt]=Laxt[u]; Laxt[u]=cnt; To[cnt]=v; } void dfs(int u) //Fluery算法 { for(int i=Laxt[u];i;i=Next[i]){ if(!used[i]){ used[i]=1; dfs(To[i]); } } path[++num]=u; } int main() { int n,i,j,L;bool Flag=false; scanf("%d",&n); for(i=1;i<=n;i++){ scanf("%s",c); L=strlen(c); if(L==1){ cout<<c[0]; Flag=true; } s1=s2=""; for(j=0;j<L-1;j++)s1+=c[j]; for(j=1;j<L;j++) s2+=c[j]; if(mp.find(s1)==mp.end()) mp[s1]=++tot,name[tot]=s1; if(mp.find(s2)==mp.end()) mp[s2]=++tot,name[tot]=s2; a[i]=mp[s1];b[i]=mp[s2]; od[a[i]]++;id[b[i]]++; add(a[i],b[i]); } if(Flag) { cout<<endl;return 0;} //只有单个字母,坑了我好久 int S=1,c1=0,c2=0; for(i=1;i<=tot;i++){ if(od[i]-id[i]==1) c1++,S=i; else if(od[i]-id[i]==-1) c2++; else if(od[i]-id[i]!=0) c1=3; } if(!((c1==0&&c2==0)||(c1==1&&c2==1))) cout<<"NO"<<endl;//不满足欧拉路 else{ dfs(S); if(num!=n+1) cout<<"NO"<<endl; //不连通(也可以用并查集做) else { cout<<name[S]; for(i=num-1;i>=1;i--) cout<<name[path[i]][L-2]; } } return 0; }