动态规划(判定DP)
——牛客21303
题目描述
给你一个合法的括号序列s1,每次你可以删除一个"()"
你可以删除0个或者多个"()"
求能否删成另一个括号序列s2
输入描述:
第一行输入一个字符串s (2 ≤ |s| ≤ 100)
第二行输入一个字符串t (2 ≤ |t| ≤ 100 )
输出描述:
如果可以输出"Possible"
否则输出"Impossible"
示例1
输入
(())
()
输出
Possible
示例2
输入
()
()
输出
Possible
示例3
输入
(()()())
((()))
输出
Impossible
示例4
输入
((())((())())())
(()(())())
输出
Possible
示例5
输入
((())((())())())
((()()()()()))
输出
Impossible
备注:
子任务1: |s| <= 10
子任务2: |s| <= 20
子任务3: 无限
解析:
dp[i][j][k]表示当s1滑动到i时以及s2滑动到j时并且从s1中删去的k="(“的数量-”)"的数量,是否存在;
这里要注意当dp[i][j][k]=1时
当s1[i+1]=s2[j+1] 并且k=0(不然的话一定要删除,前面如果都不匹配了的话这个保留在这里肯定最后到不了要到的字符串)时,就相当于可以不删除,往后一个走所以dp[i+1][j+1][0]=1;
第二种情况: 删除(特别注意就是相等的时候可以删除)
就是在j不动的情况下(相当于去s1[i+1]后面找和这个括号相匹配的括号),删去该s1[i+1]的字母,k通过+1( 删去“(” )或者-1(删去“)” )
还有学到了一个小的技巧:scanf("%s%s",s1+1,s2+1);这样可以方便在后面处理i和j哦;所以后面都是用s1[i+1]来计算的哦,相当于初始地址就是s1+1
#include<bits/stdc++.h>
using namespace std;
int dp[200][200][55];
int main()
{
char s1[200],s2[200];
scanf("%s%s",s1+1,s2+1);
dp[0][0][0]=1;
int len1=strlen(s1+1),len2=strlen(s2+1);
for(int i=0;i<len1;i++){
for(int j=0;j<len2;j++){
for(int k=0;k<len1/2;k++){
if(dp[i][j][k]){
if(!k&&s1[i+1]==s2[j+1]) dp[i+1][j+1][0]=1;
if(s1[i+1]== '(') dp[i+1][j][k+1]=1;
//注意这里是if而不是else if(WA了我好久)解析上面有
else if(k) dp[i+1][j][k-1]=1;
}
}
}
}
if(dp[len1][len2][0]) printf("Possible\n");
else printf("Impossible\n");
return 0;
}