动态规划的问题总结

来源:互联网 发布:影楼美工 编辑:程序博客网 时间:2024/04/29 09:26

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 15000using 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 100005using 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 250using 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 5050using 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

原创粉丝点击