题目描述
给你一个合法的括号序列S1,每次你可以删除一个"()" 你可以删除0个或者多个"()" 求能否删成另一个括号序列S2 |
输入描述
第一行输入一个字符串s(2<=| s |<=100) |
第二行输入一个字符串t(2<=| t |<=100) |
输出描述
如果可以输出"Possible" |
否则输出"Impossible" |
例1
输入
输出
例2
输入
输出
例3
输入
输出
例4
输入
((( ))((( ))( ))( )) |
(( )(( ))( )) |
输出
例5
输入
((( ))((( ))( ))( )) |
((( )( )( )( )( ))) |
输出
备注
子任务1:| s |<=10 子任务2:| s |<=20 子任务3:无限制 |
思路
DP解法:创建bool型的dp[ i ][ j ]表示字符串s的前i位能否通过删括号或者不删来得到t的前j位
AC代码
#include<bits/stdc++.h>
using namespace std;
string s,t;//存储字符串s和t
int lens,lent;//字符串s和t的长度
bool dp[101][101];//bool型的dp[i][j]表示字符串s的前i位能否通过删括号或者不删来得到t的前j位
int main(){
//输入数据
cin>>s>>t;//输入字符串s和t
lens=s.size();//字符串s的长度
lent=t.size();//字符串t的长度
//dp的初始化
for(int i=0;i<=min(lens,lent);i++)dp[i][0]=1;//dp[i][0]=1可理解为s的前i位可以通过删括号或者不删来得到t的前0位,当然这里的min(lens,lent)也可替作max(lens,lent)
//推导(状态转移)
for(int i=1;i<=lens;i++){//s当前处理到第i位
for(int j=1;j<=lent;j++){//t当前处理到第j位
if(s[i-1]==t[j-1])dp[i][j]=dp[i-1][j-1];//如果这两位相等就继承共同少一位dp[i-1][j-1]的状态
if(s[i-1]==')'){//以')'为标准往前删除括号(而且题目说s必合法,无需做过多担心)
int k=i-1;//用k来往前遍历
int cnt=1;//cnt来记录‘)’比'('多多少
while(cnt>0) {//还未到删除条件
if (s[k - 1] == ')') cnt += 1;//遇‘)’加1
else cnt -= 1;//遇'('减1
k -= 1;//往前遍历
}//这里有小伙伴会问:为什么只删了就近的括号?解释:因为前边遍历的时候已经把之前的可以成括号的情况都包含进去了
dp[i][j]|=dp[k][j];//继承删完括号后长为k的s对于自己本身前j位的状态
//PS;|=的使用很关键 因为有种情况:第16行代码dp[i][j]继承dp[i-1][j-1]为真但是删完dp[k][j]为家的话,用=就会替换,导致结果出错
}
}
}
//结果的判断
if(dp[lens][lent]) cout<<"Possible"<<endl;//为真输出"Possible"
else cout<<"Impossible"<<endl;//为假输出“Impossible”
}