您的位置:首页 > 其它

hdu1501 zipper【记忆化搜索】【动态规划】

2017-10-11 20:37 411 查看

题目大意:

给三个字符串A,B,C,问A和B能否按顺序组成C;

解题思路:

冲突关键在于如果C中某字符刚好都等于枚举到的A中字符和B中字符该怎么转移。

法一:记忆化搜索。

dp[i][j]表示A枚举到i,B枚举到j时能否匹配成功。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#define ll long long
using namespace std;

int getint()
{
int i=0,f=1;char c;
for(c=getchar();(c<'0'||c>'9')&&c!='-';c=getchar());
if(c=='-')c=getchar(),f=-1;
for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0';
return i*f;
}

const int N=205;
int T,t1n,t2n,sn,dp

;
char t1
,t2
,s[N<<1];

bool dfs(int x,int y,int z)
{
if(x==t1n+1&&y==t2n+1&&z==sn+1)return true;
if(dp[x][y]!=-1)return dp[x][y];
if(s[z]==t1[x]&&s[z]==t2[y])return dp[x][y]=dfs(x+1,y,z+1)||dfs(x,y+1,z+1);
else if(s[z]==t1[x])return dp[x][y]=dfs(x+1,y,z+1);
else if(s[z]==t2[y])return dp[x][y]=dfs(x,y+1,z+1);
return dp[x][y]=false;
}

int main()
{
//freopen("lx.in","r",stdin);
T=getint();
for(int k=1;k<=T;k++)
{
memset(dp,-1,sizeof(dp));
scanf("%s%s%s",t1+1,t2+1,s+1);
t1n=strlen(t1+1);
t2n=strlen(t2+1);
sn=strlen(s+1);
printf("Data set %d: ",k);
if(!dfs(1,1,1))puts("no");
else puts("yes");
}
return 0;
}


法二:动态规划。

最优子结构分析:如果A、B可以组成C,那么C最后一个字母必定是 A 或 C 的最后一个字母组成。

C去除除最后一位,就变成是否可以求出 A-1和B 或者 A与B-1 与 是否可以构成 C-1。。。

状态转移方程: 用dp[i][j] 表示 表示A前 i 为 和B 前j 位是否可以组成 C的前i+j位        

 dp[i][j]= (dp[i-1][j]&&(a[i]==c[i+j]))||(dp[i][j-1]&&(b[j]==c[i+j]))

注意对边界的处理,初始化条件为主串长度的字符相同即为1,否则为0。

就是转移方程中i=0或j=0的情况,但i-1=-1会炸。

其意义是为判断整个A或B是C的前缀。

#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <string>
#include <iostream>

using namespace std;

const int N = 205;
const int INF = 1e8;

char str1
, str2
, str[N * 2];
int dp

;

int main()
{
int t, n, Case = 1;
scanf("%d", &t);
while(t --)
{
scanf("%s%s%s", str1 + 1, str2 + 1, str + 1);
str[0] = str1[0] = str2[0] = '0';
//     memset(dp, 0, sizeof(dp));
for(int i = 1; i < strlen(str1); i ++)
{
if(str1[i] == str[i]) dp[i][0] = 1;
else dp[i][0] = 0;
}
for(int i = 1; i < strlen(str2); i ++)
{
if(str2[i] == str[i]) dp[0][i] = 1;
else dp[0][i] = 0;
}
for(int i = 1; i < strlen(str1); i ++)
{
for(int j = 1; j < strlen(str2); j ++)
{
dp[i][j] = ((dp[i - 1][j] && str1[i] == str[i + j]) || (dp[i][j - 1] && str2[j] == str[i + j]));
}
}
if(dp[strlen(str1) - 1][strlen(str2) - 1]) printf("Data set %d: yes\n", Case ++);
else printf("Data set %d: no\n", Case ++);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: