P1019 单词接龙
11.30
今天补充了dfs的部分。记录下途中遇到的各种各样的错误:
//一开始的预处理计算match数组的部分
for(int i=1;i<n;i++){
for(int j=i+1;j<=n;j++){
mt(word[i],word[j]);
mt(word[j],word[i]);
}
}
//一开始的匹配首字母第一个单词的部分
for(int k=1;k<=n;k++){
if(begin==word[k][0]){
max_l=ans=word[k].size();
used[k]++;
dfs(k);
}
}
1.昨天为了在mt函数中能直接对match[i][j]进行修改,把i,j设成全局变量。今天反倒忘了这回事了,在main函数预处理的时候把原本写好的for循环里的i,j改成了别的名字,调试输出发现match数组全部没有经过计算。最后把i,j作为参数一并传入mt函数,解决。
2.原来两个envelope重复接也是可以的……接龙长度应为15。但上述代码中没有考虑到单词自身互接的情况,也就是不计算match[1][1]。修改一下,让i与j都是从1到n,解决。
3.又遇到了给定首字母可接多个单词的情况……然后发现上述代码中,如果更换第一个单词,max_l会被覆盖,这显然不合理(没有保存上一次接龙的结果)。只改ans就可以了。
4.dfs部分还是不会写回溯的条件……或者说没有意识到。每一次dfs都是在遍历所有单词,看看有没有单词可以接得上,如果没有,把上一个单词换掉再接(回溯),也就是说,应该增加一个判定,若遍历完所有单词依然没有一个能接得上,就应该回溯。而最长长度的判定应该发生在回溯之前,把得到的最长长度先存进max_l。
//AC代码
#include<cstdio>
#include<algorithm>
#include<string.h>
#include<string>
#include<iostream>
#include<cmath>
using namespace std;
string word[25];
int used[25];
int match[25][25];
int n,i,j,max_l=0,ans=0;
void mt(string str1,string str2,int l,int r)
{
match[l][r]=0;
int lenth1=str1.size();
int lenth2=str2.size();
int y,link=0;
for(y=0;y<lenth2;y++){
if(str1[lenth1-1]==str2[y]&&y<lenth2-1){
match[l][r]++;
link=1;
break;
}
}
if(link){
for(int p=lenth1-2,q=y-1;p>=0&&q>=0;p--,q--){
if(str1[p]!=str2[q]){
link=0;
break;
}
if(p==0&&str1[p]==str2[q]){
link=0;
break;
}
match[l][r]++;
}
if(link==0) match[l][r]=0;
}
}
void dfs(int k)
{
bool ok=false;
for(int l=1;l<=n;l++){
if(match[k][l]>0&&used[l]<2){
//cout << word[l] <<endl;
ans+=word[l].size()-match[k][l];
used[l]++;
ok=true;
dfs(l);
used[l]--;
ans-=word[l].size()-match[k][l];
}
}
if(ok==false) max_l=max(ans,max_l);
return;
}
int main()
{
memset(match,-1,sizeof(match));
scanf("%d",&n);
for(int k=1;k<=n;k++){
cin >> word[k];
}
char begin;
scanf(" %c",&begin);
for(i=1;i<=n;i++){
for(j=1;j<=n;j++){
if(match[i][j]==-1) mt(word[i],word[j],i,j);
// printf("match[%d][%d]=%d\n",i,j,match[i][j]);
if(match[j][i]==-1) mt(word[j],word[i],j,i);
// printf("match[%d][%d]=%d\n",j,i,match[j][i]);
}
}
for(int k=1;k<=n;k++){
if(begin==word[k][0]){
ans=word[k].size();
used[k]++;
dfs(k);
}
}
printf("%d",max_l);
return 0;
}
11.29
被这题整得头大。主要是又涉及字符串又涉及dps搞得整个人都很烦躁。
核心要点不在dps而在求两个单词间的匹配长度,于是把大问题拆分成小问题,先写个程序,要求:
输入n行单词(每行一个),求给定的第i个单词的尾部与第j个单词头部之间的匹配长度,且要求前者不能完全包含后者,后者不能完全包含前者。若不能匹配,输出0;
于是恶补了一下string类型,样例还是能过的
#include<cstdio>
#include<algorithm>
#include<string.h>
#include<string>
#include<iostream>
#include<cmath>
using namespace std;
string word[25];
int match[25][25];
int n,i,j;
void mt(string str1,string str2)
{
match[i][j]=0;
int lenth1=str1.size();
int lenth2=str2.size();
int y,link=0;
for(y=0;y<lenth2;y++){
if(str1[lenth1-1]==str2[y]&&y<lenth2-1){ //这里已排除了前者将后者完全包含的情况
match[i][j]++;
link=1;
break;
}
}
if(link){
for(int p=lenth1-2,q=y-1;p>=0&&q>=0;p--,q--){
if(str1[p]!=str2[q]){
link=0;
break;
}
if(p==0&&str1[p]==str2[q]){//排除后者将前者包含的情况
link=0;
break;
}
match[i][j]++;
}
if(link==0) match[i][j]=0;
}
}
int main()
{
memset(match,-1,sizeof(match));
scanf("%d",&n);
for(int k=1;k<=n;k++){
cin >> word[k];
}
//char begin;
//scanf("%c",&begin);
while(1){
scanf("%d%d",&i,&j);
if(match[i][j]==-1) mt(word[i],word[j]);
printf("%d\n",match[i][j]);
}
return 0;
}