題目大意:定義一些規則序列:如果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 1000000000char 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 startfor(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;}