ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

2192:Zipper DP+DFS

2021-10-22 21:01:26  阅读:182  来源: 互联网

标签:int s2 s1 DFS s3 2192 个字符 Zipper dp


2192:Zipper

#include <bits/stdc++.h>
using namespace std;
//0、状态是什么?怎么表示 
//1、分解成子问题 
//2、无后效性,一种状态A只与另一种状态B的值有关,与状态B的到达方式无关 
string s1,s2,s3;//用string 声明字符串就不用考虑字符串长度 
int len1,len2,len3;
int dp[205][205];// dp[i][j]为1或0表示s1前i个字符段与 s2前j个字符段 是否匹配成功,这就是状态 
int main(int argc, char** argv) {
	int t;
	cin>>t;
	for(int k=1;k<=t;k++){
		memset(dp,0,sizeof(dp));
		cin>>s1>>s2>>s3;
		len1=s1.size();//strlen()是用于char a[100];这样声明数组的时候噢 
		len2=s2.size();
		len3=s3.size();
//试想,如果s1前i个字符段与 s2前j个字符段匹配成功,则s3[i+j]要么等于s1[i]
//,要么等于 s2[j],同理判断dp[i][j]应该判断 
	/*
		for(int i=0;i<=len1;i++){
			dp[i][0]=1;
		}
		for(int j=0;j<=len2;j++){
			dp[0][j]=1;
		}
	 
//一则,只要一个字符串为空,只有0个字符,一定匹配成功
//二则,判断 s1前i个字符段与 s2前j个字符段是否匹配成功时,要考虑dp[i-1][j-1]
//,如果是 s1或s2只有一个字符,判断s1[i]或s2[j]==s3[i+j]就够了 不需要讨论除去
//s1[i]和s2[j]之后的两段字符串匹配情况,因为其中一个串没有字符了,一定匹配 
		for(int i=1;i<=len1;i++){
			for(int j=1;j<=len2;j++){
//				if(s1[i]==s3[i+j]&&dp[i-1][j]==1)dp[i][j]=1; 
//				if(s2[j]==s3[i+j]&&dp[i][j-1]==1)dp[i][j]=1; 
			if(s1[i]==s3[i+j])dp[j + 1][k] = dp[j][k] || dp[j + 1][k]; 
			if(s2[j]==s3[i+j])dp[j][k + 1] = dp[j][k] || dp[j][k + 1]; 
				
			}
		} 
错了,并非只要s1,s2有一个为空就一定匹配,匹不匹配要看给的s3!!!!!哪!!!!!!!!
还有,动态规划递推总是想让数组存储下标从1开始,好让状态表示的意义与实际意义相同
但应该考虑考虑,状态里是否有这种0的情况,比如,长度为0的字符串与另一个字符串找公共子串
再比如此题, s1或s2只有0个字符,能否与另一个字符串匹配出s3 
		*/
//		递推总要初始化一些边界值 
			dp[0][0]=1;
			for(int i=0;i<=len1;i++){
			for(int j=0;j<=len2;j++){
		
		//由于数组下标从0开始,这里表示的含义要格外注意,s[i]表示的是s字符串中第i+1个字符
//而dp[i][j]则表示s1字符串中前i个字符与s2字符串中前j个字符是否匹配!!!
//这个二重循环是为了递推补充dp数组的数据,自然要按dp数组的下标来 此时就要注意
//s数组下标与dp数组下标的关系 

			if((i<len1&&s1[i]==s3[i+j])&&dp[i][j])dp[i+1][j]=1;
//也就是说s1字符串中前i个字符与s2字符串中前j个字符匹配并且s3中第i+j+1个数据是
//s1的第i+1个元素 
			if((j<len2&&s2[j]==s3[i+j])&&dp[i][j])dp[i][j+1]=1;
			}
		}
		if(dp[len1][len2]==1)printf("Data set %d: yes\n",k);
		else printf("Data set %d: no\n",k);
	} 
	return 0;
}


原来提交时的代码中有如此琐碎长篇的注释,还会出现runtime error~~
错误思想:
//一则,只要一个字符串为空,只有0个字符,一定匹配成功
//二则,判断 s1前i个字符段与 s2前j个字符段是否匹配成功时,要考虑dp[i-1][j-1]
//,如果是 s1或s2只有一个字符,判断s1[i]或s2[j]==s3[i+j]就够了 不需要讨论除去
//s1[i]和s2[j]之后的两段字符串匹配情况,因为其中一个串没有字符了,一定匹配

		for(int i=1;i<=len1;i++){
			for(int j=1;j<=len2;j++){
//				if(s1[i]==s3[i+j]&&dp[i-1][j]==1)dp[i][j]=1; 
//				if(s2[j]==s3[i+j]&&dp[i][j-1]==1)dp[i][j]=1; 
			if(s1[i]==s3[i+j])dp[j + 1][k] = dp[j][k] || dp[j + 1][k]; 
			if(s2[j]==s3[i+j])dp[j][k + 1] = dp[j][k] || dp[j][k + 1]; 
				
			}
		} 

×××××××××××××××
Reason:错了,并非只要s1,s2有一个为空就一定匹配,匹不匹配要看给的s3!!!哪!!!!!!
还有,动态规划递推总是想让数组存储下标从1开始,好让状态表示的意义与实际意义相同
但应该考虑考虑,状态里是否有这种0的情况,比如,长度为0的字符串与另一个字符串找公共子串
再比如此题, s1或s2只有0个字符,能否与另一个字符串匹配出s3

由于数组下标从0开始,这里表示的含义要格外注意,s[i]表示的是s字符串中第i+1个字符
//而dp[i][j]则表示s1字符串中前i个字符与s2字符串中前j个字符是否匹配!!!
//这个二重循环是为了递推补充dp数组的数据,自然要按dp数组的下标来 此时就要注意
//s数组下标与dp数组下标的关系

		if((i<len1&&s1[i]==s3[i+j])&&dp[i][j])dp[i+1][j]=1;

//也就是说s1字符串中前i个字符与s2字符串中前j个字符匹配并且s3中第i+j+1个数据是
//s1的第i+1个元素

递推总要初始化一些边界值 ,再依据已知的值去递推其他的数据呀!
想想数字三角形的最下边一行

思想还是比较混乱,但对下一道题还是那么的跃跃欲试!

最后附上这道题的DFS解法,就当是提前了解以下DFS深度优先搜索算法

#include <bits/stdc++.h>
using namespace std; 
string s1,s2,s3;//用string 声明字符串就不用考虑字符串长度 
int len1,len2,len3;
int flag;
void DFS(int i,int j,int k){
	if(k==len3){
		flag=1;
		return ;
	}
	if(s1[i]==s3[k])DFS(i+1,j,k+1);
	 if(s2[j]==s3[k])DFS(i,j+1,k+1);
	 return ;
}
int main(int argc, char** argv){
	int t;
	cin>>t;
	for(int k=1;k<=t;k++){
		flag=0;
		cin>>s1>>s2>>s3;
		len1=s1.size();//strlen()是用于char a[100];这样声明数组的时候噢 
		len2=s2.size();
		len3=s3.size();
		DFS(0,0,0);
		if(flag==1)printf("Data set %d: yes\n",k);
		else printf("Data set %d: no\n",k);
	} 
	return 0;
}

会超时
——用时间换空间
所以增加一个判断是否访问过的数组flag

#include <bits/stdc++.h>
using namespace std; 
string s1,s2,s3;//用string 声明字符串就不用考虑字符串长度 
int len1,len2,len3;
int fla;
int flag[205][205];
void DFS(int i,int j,int k){
	if(flag[i][j]==0)
{
		if(k==len3){
		fla=1;
		return ;
	}
	if(s1[i]==s3[k])DFS(i+1,j,k+1);
	 if(s2[j]==s3[k])DFS(i,j+1,k+1);
	 flag[i][j]=1;
}
	 return ;
}
int main(int argc, char** argv){
	int t;
	cin>>t;
	for(int k=1;k<=t;k++){
		fla=0;
		memset(flag,0,sizeof(flag));
		cin>>s1>>s2>>s3;
		len1=s1.size();//strlen()是用于char a[100];这样声明数组的时候噢 
		len2=s2.size();
		len3=s3.size();
		DFS(0,0,0);
		if(fla==1)printf("Data set %d: yes\n",k);
		else printf("Data set %d: no\n",k);
	} 
	return 0;
}


时间换空间的原理我懂,但是没太想明白,为什么会重复判断
s1[i], s2[j]是否匹配呢???

标签:int,s2,s1,DFS,s3,2192,个字符,Zipper,dp
来源: https://blog.csdn.net/qq_51070956/article/details/120912023

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有