题目链接:http://poj.org/problem?id=1141
题意:给定一括号序列,求出添加括号数最小的完整序列
解法:区间DP
定义dp[i][j]表示题目所给字符串s中从左至右字符i至j这一区间段括号序列构成完整序列所需添加的最小括号数;
根据i与j的大小对dp[i][j]进行初始化,i==j显然为1,i>j不符合定义中从左至右意为空序列即0,i<j因是取最小值则初值设为相对较大;
设阶段r为序列长度,状态为i为当前子序列的首指针,可得尾指针j=i+r;
可得状态转移方程f:dp[i][j]=min(dp[i][k](i~k区间),dp[k+1][j](k+1~j区间)) i<=k<j;
首先进行整体区间判断若(s[i]=='('&&s[j]==')')||(s[i]=='['&&s[j]==']')即可得dp[i][j]=dp[i+1][j-1],再结合f得出dp[i][j];
因为题目要求输出所得完整序列故定义v[i][j]表示k的取值,k为分开i~j区间使dp[i][j]取最小值时的k,初始设为-1,递归输出即可;
#include<iostream> #define N 10000000 using namespace std; int dp[405][405],v[405][405],n; string s; void print(int l,int r){ if(l>r) return; if(l==r){ if(s[l]=='('||s[l]==')') cout<<"()"; else cout<<"[]"; return; } if(v[l][r]==-1){ cout<<s[l]; print(l+1,r-1); cout<<s[r]; } else{ int k=v[l][r]; print(l,k); print(k+1,r); } } int main(){ cin>>s; n=s.size(); for(int i=0;i<205;i++) for(int j=0;j<205;j++){ if(i==j) dp[i][j]=1; else { if(i>j) dp[i][j]=0; else dp[i][j]=N; } v[i][j]=-1; } for(int i=1;i<n;i++) for(int l=0;l+i<n;l++){ int r=l+i; if((s[l]=='('&&s[r]==')')||(s[l]=='['&&s[r]==']')) dp[l][r]=dp[l+1][r-1]; for(int j=l;j<r;j++){ if(dp[l][r]>dp[l][j]+dp[j+1][r]){ dp[l][r]=dp[l][j]+dp[j+1][r]; v[l][r]=j; } } } print(0,n-1); cout<<endl; return 0; }