题目描述
单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中出现两次),在两个单词相连时,其重合部分合为一部分,例如 beast和astonish,如果接成一条龙则变为beastonish,另外相邻的两部分不能存在包含关系,例如at 和 atide 间不能相连。
输入输出格式
输入格式:
输入的第一行为一个单独的整数n (n<=20)表示单词数,以下n 行每行有一个单词,输入的最后一行为一个单个字符,表示“龙”开头的字母。你可以假定以此字母开头的“龙”一定存在.
输出格式:
只需输出以此字母开头的最长的“龙”的长度
输入输出样例
输入样例#1:
5
at
touch
cheat
choose
tact
a
输出样例#1:
23 (连成的“龙”为atoucheatactactouchoose)
说明
NOIp2000提高组第三题
#include<iostream>
#include<cstdio>
using namespace std;
string s[25];
int n,side[25][25],mx,vis[25];
inline string read()
{
string ss="";
char ch=getchar();
while(ch=='\n'||ch=='\r'||ch==' ')
ch=getchar();
while(ch!='\n'&&ch!='\r')
{
if(ch!=' ')
ss.push_back(ch);
ch=getchar();
if(ch==EOF)
break;
}
return ss;
}
void calc(int i,int j)
{
int len=s[i].length() <s[j].length()?len=s[i].length() :s[j].length();
int k,l=0;
while(l<len)
{
l++; //l是尾部和首部相等的长度
for(k=0;k<l;k++) //l从1开始,如果可以接成,那一定是最长的
if(s[i][s[i].length()-1-k]!=s[j][l-1-k])//从后往前进行判断
break;
if(k==l) //表示能接上
{
side[i][j]=s[j].length() -l;
break;
}
}
if(i>j) calc(j,i);//除去等于的情况,额。
}
void dfs(int i,int len)
{
if(len>mx)
mx=len;
for(int j=0;j<n;j++)
{
if(side[i][j]>0 && vis[j]<2)
{
vis[j]++;
dfs(j,len+side[i][j]); //传递新的长度
vis[j]--;
}
}
}
int main()
{
scanf("%d",&n);
for(int i=0;i<=n;i++)
{
s[i]=read();
for(int j=0;j<=i;j++)//循环的时候很巧妙,连接的时候包括它自己
{
calc(i,j);
}
}
dfs(n,1);
cout<<mx<<endl;
return 0;
}
2
ho
hoooppp
h
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
char s[25][35];
int n,side[25][25],mx,v[25];
void cal(int i,int j)
{
int k,len=0,l=0;
int len1=strlen(s[i]);
int len2=strlen(s[j]);
len=len1<len2?len1:len2;
while(++l<=len)//l假设首尾相同的数目
{
for(k=0;k<l;k++)
{
if(s[i][len1-1-k]!=s[j][l-1-k])//...abc abc....
break;
}
if(k==l) side[i][j]=len2-l;
}
}
void dfs(int t,int len)
{
if(len>mx) {mx=len;}
for(int i=0;i<n;i++)
{
if(side[t][i]>0 && v[i]<2)
{
v[i]++;
// cout<<s[t]<<","<<s[i]<<","<<len<<","<<side[t][i]<<endl;
dfs(i,len+side[t][i]);
v[i]--;
}
}
}
int main()
{
scanf("%d",&n);
for(int i=0;i<=n;i++)//最后一个是龙的开头
{
scanf("%s",s[i]);
for(int j=0;j<=i;j++)
{
cal(i,j);
if(i!=j) cal(j,i);
}
}
dfs(n,1);//龙的开头一个字母,长度为1
cout<<mx<<endl;
}
分部,先求首尾相同的,错误代码,如何中间输出,查找错误
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
char s[25][35];
int n,side[25][25],mx,vis[25];
void cal(int i,int j)
{
int k,len=0;
int len1=strlen(s[i]);
int len2=strlen(s[j]);
len=len1<len2?len1:len2;
for(k=0;k<len;k++)
{
if(s[i][len1-1-k]!=s[j][k])
break;
}
if(k==0) side[i][j]=0;//没有首尾相同的,连接值为0
else side[i][j]=len2-k;
}
int main()
{
scanf("%d",&n);
for(int i=0;i<=n;i++)//最后一个是龙的开头
{
scanf("%s",s[i]);
for(int j=0;j<=i;j++)
{
cal(i,j);
if(i!=j) cal(j,i);
cout<<s[i]<<","<<s[j]<<","<<side[i][j]<<endl;
cout<<s[j]<<","<<s[i]<<","<<side[j][i]<<endl;
cout<<endl;
}
}
}