UVA 1626 区间dp、打印路径

uva

紫书例题,这个区间dp最容易错的应该是(S)这种匹配情况,如果不是题目中给了提示我就忽略了,只想着左右分割忘记了这种特殊的例子。

dp[i][j]=MIN{dp[i+1][j-1] | if(match(i,j) , dp[i][k]+dp[k+1][j] | i<=k<=j .}
注意初始化dp[i][i]=1,表示1个字符最少需要一个才能匹配,dp[i+1][i]=0,因为可能只有两个字符使得i+1>j-1,我们可以认为中间是空字符已经匹配了。

打印路径利用了递归,很巧妙,lrj的代码确实短小精悍。

还有就是本题的输入输出要注意,可能出现空串,输入的每一行字符间(包括第一行字符和t之间)都要键入一个空格,输出每两个答案之间输出一个空格。

为了防止getline()将输入的t读入到s中,我们将t以字符形式读入。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define inf 0x3f3f3f3f
 4 int dp[110][110];
 5 char s[115];
 6 bool match(int i,int j)
 7 {
 8     return (s[i]=='['&&s[j]==']')||(s[i]=='('&&s[j]==')');
 9 }
10 void print(int l,int r)
11 {
12  if(l>r) return;
13  if(l==r){
14     if(s[l]=='['||s[r]==']') printf("[]");
15     else printf("()");
16     return;
17  }
18  if(dp[l][r]==dp[l+1][r-1]&&match(l,r)){
19     printf("%c",s[l]);
20     print(l+1,r-1);
21     printf("%c",s[r]);
22     return;
23  }
24  for(int k=l;k<=r;++k){
25     if(dp[l][r]==dp[l][k]+dp[k+1][r]){
26         print(l,k);
27         print(k+1,r);
28         return;
29     }
30  }
31 }
32 int main()
33 {
34     int t,n,m=0,i,j,k;
35     cin.getline(s,105);
36     t=atoi(s);
37     while(t--){getchar();m++;
38     if(m>1) puts("");
39     cin.getline(s+1,105);
40         n=strlen(s+1);
41         memset(dp,inf,sizeof(dp));
42         for(i=0;i<=n;++i)
43         {
44             dp[i][i]=1;
45             dp[i+1][i]=0;
46         }
47         for(int len=2;len<=n;++len)
48         {
49             for(i=1,j=len;j<=n;++i,++j)
50             {
51                 if(match(i,j)) dp[i][j]=min(dp[i][j],dp[i+1][j-1]);
52                 for(k=i;k<=j;++k)
53                 {
54                    dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]);
55                 }
56             }
57         }
58         //cout<<dp[1][n]<<endl;
59         print(1,n);puts("");
60     }
61     return 0;
62 }
原文地址:https://www.cnblogs.com/zzqc/p/7323863.html