【DFS】字符串匹配

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;
}
发布了28 篇原创文章 · 获赞 0 · 访问量 671

猜你喜欢

转载自blog.csdn.net/weixin_45561591/article/details/103319883