动态规划的问题总结

1、dp[个数][weight] (例子:poj 1837 Balance)
dp[i][w]=relate to (dp[i-1][w-c[j]])
这道题中dp存储的不是weight,而是方法个数

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<algorithm>
#define MAXNUM 15000
using namespace std;
int dp[25][MAXNUM], C, G, good[25], w[25];
int main()
{
    //freopen("1.txt", "r", stdin);
    int i, j, k, a, b, c, sum, cases;
    scanf("%d%d", &C, &G);
    for (i = 1; i <= C; i++)
        scanf("%d", &good[i]);
    for (i = 1; i <= G; i++)
        scanf("%d", &w[i]);
    dp[0][7500] = 1;
    for (i = 1; i <= G; i++)
    {
        for (j = 0; j <= MAXNUM; j++)
        {
            if (dp[i - 1][j])
            {
                for (k = 1; k <= C; k++)
                    dp[i][j + good[k] * w[i]] += dp[i - 1][j];
            }

        }
    }
    printf("%d\n", dp[G][7500]);
    return 0;
}

2、dp[所有可能的值] (例子:poj 1276 Cash Machine)
if(dp[i]) dp[i+w[t]*k]=1; 有时候Bool类型更好

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<algorithm>
#define CASH 100005
using namespace std;
bool dp[CASH];
int N, cash, n[20], D[20];
int main()
{
    //freopen("1.txt", "r", stdin);
    int i, j, k, a, b, c, res;
    while (scanf("%d%d", &cash, &N) != EOF)
    {
        memset(dp, 0, sizeof(dp));
        memset(n, 0, sizeof(n));
        memset(D, 0, sizeof(D));
        for (i = 0; i < N; i++)
            scanf("%d%d", &n[i], &D[i]);
        if (!N || !cash)
        {
            printf("0\n");
            continue;
        }
        res = 0;
        dp[0] = 1;
        for (i = 0; i < N; i++)
        {
            for (j = res; j >= 0; j--)
            {
                if (dp[j])
                for (k = 1; k <= n[i]; k++)
                {
                    a = j + k*D[i];
                    if (a <= cash)
                    {
                        dp[a] = 1;
                        res = max(res, a);
                    }
                }
            }
        }
        printf("%d\n", res);
    }
    return 0;
}

3、3276 The Cow Lexicon
dp[i]=dp[j]+w[i,j] / dp[i]=dp[j]+w[j,i] 一个是倒着,一个是顺着
dp[i]=dp[i+1]+1 //把这个给删除了
dp[i]=dp[j]+j-i-len //i~j的串删除一些字符后能和Len匹配的

#include<iostream>
#include<vector>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<string>
#include<math.h>
using namespace std;
int dp[305], W, L;
char ss[305];
string strs[610];
int main()
{
    //freopen("1.txt", "r", stdin);
    int i, j, k, t, a, b, len, flag;
    while (scanf("%d%d", &W, &L) != EOF)
    {
        memset(dp, 0, sizeof(dp));
        //memset(ss, 0, sizeof(ss));
        scanf("%s", ss);
        for (i = 0; i < W; i++)
            cin >> strs[i];

        for (i = L - 1; i >= 0; i--)
        {
            dp[i] = dp[i + 1] + 1;
            for (j = 0; j < W; j++)
            {
                len = strs[j].length();
                if (len <= L - i&&ss[i] == strs[j][0])
                {
                    int pm = i;
                    int pi = 0;
                    while (pi < len&&pm < L)
                    {
                        if (ss[pm++] == strs[j][pi])
                            pi++;
                        if (pi == len)
                        {
                            dp[i] = min(dp[i], dp[pm] + pm - i - len);
                            break;
                        }
                    }
                }
            }
        }
        printf("%d\n", dp[0]);
    }
    return 0;
}

4 、POJ 1836 Alignment
难一些的最大上升子序列
大神的图

顺着求一次最大上升子序列dpl,倒着求一次最大上升子序列dpr,然后求dpl[i]+dp=i”>j的最大值
(别人的代码,参考博客:http://blog.csdn.net/lin375691011/article/details/11137083)

#include <stdio.h>
#include <string.h>
const int MAX=1005;
int main()
{
    int n,dpl[MAX],dpr[MAX];
    double hi[MAX];
    while(scanf("%d",&n)!=EOF)
    {
        int i,j;
        for(i=0; i<n; i++)
        {
            scanf("%lf",&hi[i]);
        }
        memset(dpr,0,sizeof(dpr));
        memset(dpl,0,sizeof(dpl));
        dpl[0]=1;
        for(i=1;i<n;i++)
        {
            dpl[i]=1;
            for(j=i-1;j>=0;j--)
            {
               if(hi[j]<hi[i]&&dpl[j]+1>dpl[i])
               {
                   dpl[i]=dpl[j]+1;
               }
            }
        }
        dpr[n-1]=1;
        for(i=n-2;i>=0;i--)
        {
            dpr[i]=1;
            for(j=i+1;j<=n-1;j++)
            {
               if(hi[j]<hi[i]&&dpr[j]+1>dpr[i])
               {
                   dpr[i]=dpr[j]+1;
               }
            }
        }
        int ans=dpl[n-1];
        for(i=0;i<n-1;i++)
        {
            for(j=i+1;j<n;j++)
            {
                if(dpl[i]+dpr[j]>ans)
                {
                    ans=dpl[i]+dpr[j];
                }
            }
        }
        printf("%d\n",n-ans);
    }
    return 0;
}

5 、POJ 1260 Pearls
题目有点难懂,懂了之后就是dp[i]=dp[j]+w[i,j]的最小值,遍历j

#include<iostream>
#include<vector>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<string>
#include<math.h>
using namespace std;
int price[110], num[110], dp[110], sum[110];
int main()
{
    //freopen("1.txt", "r", stdin);
    int i, j, k, t, tmp, cases;
    scanf("%d", &cases);
    while (cases > 0)
    {
        memset(price, 0, sizeof(price));
        memset(num, 0, sizeof(num));
        memset(sum, 0, sizeof(sum));
        memset(dp, 0, sizeof(dp));
        scanf("%d", &k);
        for (i = 1; i <= k; i++)
        {
            scanf("%d%d", &num[i], &price[i]);
            sum[i] = sum[i - 1] + num[i];
        }

        dp[1] = (num[1] + 10) * price[1];
        for (i = 2; i <= k; i++)
        {
            dp[i] = (num[i] + 10) * price[i] + dp[i - 1];
            for (j = 0; j < i - 1; j++)
            {
                tmp = (sum[i] - sum[j] + 10)*price[i] + dp[j];
                dp[i] = min(dp[i], tmp);
            }
        }
        cases--;
        printf("%d\n", dp[k]);
    }
    return 0;
}

dp 数组的memset很重要!!!!!!!

6 、POJ 1080 Human Gene Functions
编辑距离的变式

#include<iostream>
#include<vector>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<string>
#include<math.h>
#define MAXNUM 250
using namespace std;
int dp[MAXNUM][MAXNUM];
char str1[MAXNUM], str2[MAXNUM];
int rep1[MAXNUM], rep2[MAXNUM];
int insert[4] = { -3, -4, -2, -1 };
int contrast[4][4] = { { 5, -1, -2, -1 }, { -1, 5, -3, -2 }, { -2, -3, 5, -2 }, { -1, -2, -2, 5 } };
int main()
{
    //freopen("1.txt", "r", stdin);
    int i, j, k, t, tmp1, tmp2, cases, len1, len2;
    scanf("%d", &cases);
    while (cases > 0)
    {
        memset(rep1, 0, sizeof(rep1));
        memset(rep2, 0, sizeof(rep2));
        memset(dp, 0, sizeof(dp));
        scanf("%d%s", &len1, str1 + 1);
        for (i = 1; i <= len1; i++)
        {
            if (str1[i] == 'A')
                rep1[i] = 0;
            else if (str1[i] == 'C')
                rep1[i] = 1;
            else if (str1[i] == 'G')
                rep1[i] = 2;
            else if (str1[i] == 'T')
                rep1[i] = 3;
        }
        scanf("%d%s", &len2, str2 + 1);
        for (i = 1; i <= len2; i++)
        {
            if (str2[i] == 'A')
                rep2[i] = 0;
            else if (str2[i] == 'C')
                rep2[i] = 1;
            else if (str2[i] == 'G')
                rep2[i] = 2;
            else if (str2[i] == 'T')
                rep2[i] = 3;
        }
        dp[0][0] = 0;
        for (i = 1; i <= len1; i++)
        {
            dp[i][0] = insert[rep1[i]] + dp[i - 1][0];
        }
        for (i = 1; i <= len2; i++)
        {
            dp[0][i] = insert[rep2[i]] + dp[0][i - 1];
        }
        for (i = 1; i <= len1; i++)
        for (j = 1; j <= len2; j++)
        {
            tmp1 = dp[i][j - 1] + insert[rep2[j]];
            tmp2 = dp[i - 1][j] + insert[rep1[i]];
            tmp1 = max(tmp1, tmp2);
            tmp2 = dp[i - 1][j - 1] + contrast[rep1[i]][rep2[j]];
            dp[i][j] = max(tmp1, tmp2);;
        }
        printf("%d\n", dp[len1][len2]);
        cases--;

    }
    return 0;
}

7、poj 1159 Palindrome
这道题我以为是一个字符串和他的反向字符串求编辑距离的问题,但是仔细想想就不对,ab字符串和ba字符串的编辑距离就是2,而实际上需要添加的字符个数其实只有1个,所以仔细想想应该也可以用编辑距离的模板去套用,不过目的是求一个字符串和他的反向字符串得公共最大字符串长度n,然后用字符串的长度L减去n就是最后的结果,比如说Ab3bd与db3bA的公共子串是b3b,为3,5-3=2就为最后的结果。
Accepted 184K 891MS
//这也告诉了我一种新的关于求公共子序列的方法哈哈

#include<iostream>
#include<vector>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<string>
#include<math.h>
#define MAXNUM 5050
using namespace std;
int dp[2][MAXNUM], N;
char str1[MAXNUM], str2[MAXNUM];
int main()
{
    //freopen("1.txt", "r", stdin);
    int i, j, k, t, tmp1, tmp2, cases, len;
    while (scanf("%d", &N) != EOF)
    {
        memset(dp, 0, sizeof(dp));
        memset(str1, 0, sizeof(str1));
        memset(str2, 0, sizeof(str2));
        scanf("%s", str1 + 1);
        len = N;
        for (i = 1; i <= len; i++)
            str2[i] = str1[len + 1 - i];
        for (i = 1; i <= len; i++)
        {
            dp[1][0] = 0;
            for (j = 1; j <= len; j++)
            {
                if (str1[i] == str2[j])
                    dp[1][j] = dp[0][j - 1] + 1;
                else
                {
                    tmp1 = max(dp[0][j], dp[1][j - 1]);
                    dp[1][j] = max(tmp1, dp[0][j - 1]);
                }

            }
            for (j = 0; j <= len; j++)
                dp[0][j] = dp[1][j];
        }
        printf("%d\n", N - dp[1][len]);
    }
    return 0;
}

动态规划—->最优二分检索树
http://blog.csdn.net/ncepuzhuang/article/details/8924369
代码:
http://blog.csdn.net/sunkun2013/article/details/49908585

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值