现在的位置: 首页 > 综合 > 正文

POJ 1141 DP

2013年11月16日 ⁄ 综合 ⁄ 共 2274字 ⁄ 字号 评论关闭

DP问题实现的要点就是, 先求子问题。

设dp[i,j]为从位置i到位置j需要加入字符的最小次数,有dp[i,j]=min(dp[i,k]+dp[k+1,j]),其中i<=k<j。特别的当s[i]='[' s[j]=']'或者s[i]='(' s[j]=')'时,dp[i,j]=dp[i+1,j-1]。初始条件为dp[i,i]=1,其中0<=i<len。

如上述这题的dp方程

发现dp[i][j]依赖于两个dp[i][k], dp[k+1][j]

因此要先求所依赖的这两项才行。

想办法怎么能先求这两项,只能是枚举串长度,从2到n

类似矩阵链乘法。

其余的DP题也都是,看看怎么先求子问题,如果直接循环就搞定,比如一般的题都只依赖于前一个,那么循环就完事了。就ok。不然比如这题依赖两个,那么要考虑怎么先求解子问题了。

这道题有个易错点,就是

str[i] == '(' && str[j] == ')'时候,或者

str[i] == '[' && str[j] == ']'时候,就是两端恰好配对的时候

并不能任务dp[i][j] = dp[i+1][j-1]。 反例就是()()这种情况

而是无论什么时候都要用k做分割,然后两端相等的时候dp[i][j] = min(dp[i][j], dp[i+1][j-1]),并且把path[i][j] = -1(如果dp[i][j]选了dp[i+1][j-1])。

之前写成if-else了就WA了

dp[i][j] = min(dp[i][k], dp[k+1][j])       i<=k<j

dp[i][j] = min(dp[i][j], dp[i+1][j-1])

#include <iostream>
#include <memory>
#include <algorithm>
#include <string>
#include <cstring>
#include <cstdio>
#include <climits>

using namespace std;

const int MAXN = 110;
char str[MAXN];
int dp[MAXN][MAXN],path[MAXN][MAXN];

void print(int i, int j)
{
        if (i > j) return;
        if (i == j) {
                if (str[i] == '('|| str[i]==')') {
                        printf("()");
                        return;
                } else if (str[i] == '['||str[i]==']') {
                        printf("[]");
                        return;
                }
        }

        if (path[i][j] == -1) {
                printf("%c", str[i]);
                print(i+1, j-1);
                printf("%c", str[j]);
        } else {
                print(i, path[i][j]);
                print(path[i][j]+1, j);
        }
}

int main()
{
        int i,j,k,r,n;
        while (gets(str)) {
                n = strlen(str);
                if (n==0) {
                        printf("\n");
                        continue;
                }
                memset(dp, 0, sizeof(dp));
                memset(path, -1, sizeof(path));
                j = 0;
                for (i = 0; i < n; i++)
                        dp[i][i] = 1;
                for (r = 2; r <= n; r++)
                for (i = 0, j=i+r-1; i < n && j < n; i++, j=i+r-1) {
                                dp[i][j] = 9999999;
                                path[i][j] = -1;
                                int m;
                                for (k = i; k <j; k++) {
                                        m = dp[i][k] + dp[k+1][j];
                                        if (m < dp[i][j]) {
                                                dp[i][j] = m;
                                                path[i][j] = k;
                                        }

                                }
                                if ((str[i] == '[' && str[j] == ']') ||
                                        (str[i] == '(' && str[j] == ')')) {
                                        if (dp[i+1][j-1] < dp[i][j]) {
                                                dp[i][j] = dp[i+1][j-1];
                                                path[i][j] = -1;
                                        }
                                }
                }
                //cout<<dp[0][n-1]<<endl;
                print(0, n-1);
                printf("\n");
        }
}

抱歉!评论已关闭.