题目链接:http://poj.org/problem?id=1141
题目大意:给你一串字符串,让你补全括号,要求补得括号最少,并输出补全后的结果。
解题思路:
开始想的是利用相邻子区间,即dp[i+1][j]之类的方法求,像是求回文串的区间DP一样。然后花了3个多小时,GG。。。
错误数据:
(())(]][[)
my:6 (()()()[][][][])
ans:4 (())([][][][])
括号匹配跟回文串不同,并不能通过dp[i+1][j]或者dp[i][j-1]推得dp[i][j],可能是因为回文串必须满足称性质。
而括号匹配可能可以划分成连个任意大小的子区间而没有影响。
然后正解跟括号匹配一差不多,因为你想啊,括号匹配一求的是最多的括号对数,把原字符串长度减一下最大括号匹配数,不就是最少需要补全的括号数了嘛,我竟然想了这么久。。。
设dp[i][j]为[i,j]最少需要补齐的括号数,得到状态转移方程:
if(str[i]=='('&&str[j]==')'||str[i]=='['&&str[j]==']'){
dp[i][j]=dp[i+1][j-1];
}
dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]),(i=<k<j)
然后,如果dp[i][j]由dp[i][k]和dp[i][k+1]组成,则记录path[i][j]=k,否则记为-1,最后递归输出一下就行了。
注意:输入用while(~scanf("%s",s))会错,不知道为什么
代码
1 #include<cstdio> 2 #include<cmath> 3 #include<cctype> 4 #include<cstring> 5 #include<iostream> 6 #include<algorithm> 7 #include<vector> 8 #include<queue> 9 #include<set> 10 #include<map> 11 #include<stack> 12 #include<string> 13 #define lc(a) (a<<1) 14 #define rc(a) (a<<1|1) 15 #define MID(a,b) ((a+b)>>1) 16 #define fin(name) freopen(name,"r",stdin) 17 #define fout(name) freopen(name,"w",stdout) 18 #define clr(arr,val) memset(arr,val,sizeof(arr)) 19 #define _for(i,start,end) for(int i=start;i<=end;i++) 20 #define FAST_IO ios::sync_with_stdio(false);cin.tie(0); 21 using namespace std; 22 typedef long long LL; 23 const int N=1e3+5; 24 const int INF=0x3f3f3f3f; 25 const double eps=1e-10; 26 27 int dp[N][N],path[N][N]; 28 char str[N]; 29 30 void print(int l,int r){ 31 if(l>=r){ 32 if(l==r){ 33 if(str[l]==')'||str[l]=='(') 34 printf("()"); 35 if(str[l]==']'||str[l]=='[') 36 printf("[]"); 37 } 38 return; 39 } 40 if(path[l][r]==-1){ 41 printf("%c",str[l]); 42 print(l+1,r-1); 43 printf("%c",str[r]); 44 } 45 else{ 46 int k=path[l][r]; 47 print(l,k); 48 print(k+1,r); 49 } 50 } 51 52 int main(){ 53 while(gets(str)){ 54 memset(path,-1,sizeof(path)); 55 int n=strlen(str); 56 for(int i=0;i<=n;i++){ 57 dp[i][i]=1; 58 } 59 for(int len=1;len<n;len++){ 60 for(int i=0;i+len<n;i++){ 61 int j=i+len; 62 dp[i][j]=INF; 63 if(str[i]=='('&&str[j]==')'||str[i]=='['&&str[j]==']'){ 64 dp[i][j]=dp[i+1][j-1]; 65 } 66 for(int k=i;k<j;k++){ 67 if(dp[i][j]>dp[i][k]+dp[k+1][j]){ 68 dp[i][j]=dp[i][k]+dp[k+1][j]; 69 path[i][j]=k; 70 } 71 } 72 } 73 } 74 print(0,n-1); 75 printf(" "); 76 } 77 return 0; 78 }
附上写错的代码做个纪念,毕竟写了这么久也是有感情的。。。
1 #include<cstdio> 2 #include<cmath> 3 #include<cctype> 4 #include<cstring> 5 #include<iostream> 6 #include<algorithm> 7 #include<vector> 8 #include<queue> 9 #include<set> 10 #include<map> 11 #include<stack> 12 #include<string> 13 #define lc(a) (a<<1) 14 #define rc(a) (a<<1|1) 15 #define MID(a,b) ((a+b)>>1) 16 #define fin(name) freopen(name,"r",stdin) 17 #define fout(name) freopen(name,"w",stdout) 18 #define clr(arr,val) memset(arr,val,sizeof(arr)) 19 #define _for(i,start,end) for(int i=start;i<=end;i++) 20 #define FAST_IO ios::sync_with_stdio(false);cin.tie(0); 21 using namespace std; 22 typedef long long LL; 23 const int N=1e3+5; 24 const int INF=0x3f3f3f3f; 25 const double eps=1e-10; 26 27 int dp[N][N],path[N][N]; 28 char str[N]; 29 int flag[N]; 30 void print(int x,int y){ 31 32 if(x>=y){ 33 if(x==y) 34 flag[x]=1; 35 return; 36 } 37 int t=path[x][y]; 38 if(t==1){ 39 flag[x]=1; 40 print(x+1,y); 41 } 42 if(t==2){ 43 flag[y]=1; 44 print(x,y-1); 45 } 46 if(t==3){ 47 print(x+1,y-1); 48 } 49 if(t==4){ 50 print(x+2,y); 51 } 52 if(t==5){ 53 print(x,y-2); 54 } 55 } 56 //[)[)]] 57 int main(){ 58 while(gets(str)){ 59 int n=strlen(str); 60 memset(dp,0,sizeof(dp)); 61 memset(path,-1,sizeof(path)); 62 memset(flag,0,sizeof(flag)); 63 for(int i=1;i<=n;i++){ 64 dp[i][i]=1; 65 } 66 for(int len=1;len<n;len++){ 67 for(int i=0;i+len<n;i++){ 68 int j=i+len; 69 dp[i][j]=INF; 70 int t1=dp[i+1][j]+1,t2=dp[i][j-1]+1,t3=dp[i+1][j-1],t4=dp[i+2][j],t5=dp[i][j-2]; 71 dp[i][j]=min(dp[i][j],t1); 72 dp[i][j]=min(dp[i][j],t2); 73 if(min(t1,t2)==t1) 74 path[i][j]=1; 75 else 76 path[i][j]=2; 77 if(str[i]=='('&&str[j]==')'||str[i]=='['&&str[j]==']'&&t3<dp[i][j]){ 78 dp[i][j]=t3; 79 path[i][j]=3; 80 } 81 if(str[i]=='('&&str[i+1]==')'||str[i]=='['&&str[i+1]==']'&&t4<dp[i][j]){ 82 dp[i][j]=t4; 83 path[i][j]=4; 84 } 85 if(str[j]==')'&&str[j-1]=='('||str[j]==']'&&str[j-1]=='['&&t5<dp[i][j]){ 86 dp[i][j]=t5; 87 path[i][j]=5; 88 } 89 if(len==5) 90 cout<<"i="<<i<<" j="<<j<<" "<<dp[i][j]<<" "<<path[i][j]<<endl; 91 } 92 } 93 //printf("%d ",dp[0][n-1]); 94 print(0,n-1); 95 for(int i=0;i<n;i++){ 96 if(flag[i]){ 97 if(str[i]=='(') 98 cout<<"()"; 99 if(str[i]==')') 100 cout<<"()"; 101 if(str[i]=='[') 102 cout<<"[]"; 103 if(str[i]==']') 104 cout<<"[]"; 105 } 106 else 107 cout<<str[i]; 108 } 109 printf(" "); 110 } 111 return 0; 112 }