题目大意:定义一些规则序列:如果S是规则序列,那么[S]或者(S)也是规则序列,如果A和B都是规则序列,那么AB是规则序列。给出含有圆括号"()"和方括号"[]"的字符串
求添加最少括号的规则序列,并打印出来。
思路:含有重复子问题,递归动机的DP。
当字符串中ww[i]=='(' && ww[j]==')' 或者 ww[i]=='['&&ww[j]==']',那么显然只需要看dp[i+1][j-1]的结果即可。
dp[i][j] = min(dp[i][k] + dp[k + 1][j]), i<=k < j;
然后通过二分思想分呀分,找到中间使得dp【i】【j】最小的k,并记载下来,便于递归打印规则序列。
AC Program:
#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
#define inf 1000000000
char ww[108];
int dp[108][108];
int pos[108][108];
//dp[i][j]indicate:the characters from i to j
//the smallest length added.
void print(int a ,int b){
//cout<<a<<" "<<b<<endl;
if(a==b){
if(ww[a]=='(' ||ww[a]==')'){//lost the last half
printf("()");
}
else{
printf("[]");
}
}
if(a>=b){return;}//can't set a flag cause all leaves should be printed.
if(pos[a][b]==-1){
if(ww[a]=='('){
printf("(");
print(a+1,b-1);
printf(")");
}
else{
printf("[");
print(a+1,b-1);
printf("]");
}
}
else{
print(a,pos[a][b]);
print(pos[a][b]+1,b);
}
}
int main(){
scanf("%s",ww+1);
int n=strlen(ww+1);//from 1 to start
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
dp[i][j]=inf;
}
dp[i][i-1]=0;
dp[i][i]=1;
}
memset(pos,-1,sizeof(pos));
for(int p=1;p<=n-1;p++){
for(int i=1;i<=n-p;i++){
int j=i+p;
if((ww[i]=='('&&ww[j]==')')||(ww[i]=='[' && ww[j]==']')){
//dp[i][j]=min(dp[i][j],dp[i+1][j-1]);
if(dp[i][j]>dp[i+1][j-1]){
dp[i][j]=dp[i+1][j-1];
pos[i][j]=-1;
}
}
for(int k=i;k<=j-1;k++){
//dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]);
if(dp[i][j]>dp[i][k]+dp[k+1][j]){
dp[i][j]=dp[i][k]+dp[k+1][j];
pos[i][j]=k;
}
}
}
}
print(1,n);
printf("\n");
//cout<<pos[1][n]<<endl;
//printf("%d\n",dp[1][n]);
//system("pause");
return 0;}