动态规划集录

饭卡:

#include<algorithm>
using namespace std;
int dp[10010];
int b[10010];
int main()
{
    int a;
    while (~scanf("%d", &a) && a )
    {
        memset(dp, 0, sizeof(dp));
        memset(b, 0, sizeof(b));
        for (int i = 0; i < a; i++)
        {
            scanf("%d", &b[i]);
        }
        sort(b, b + a);
        int k;
        scanf("%d", &k);
        if (k < 5)
        {
            printf("%d\n", k);
        }
        else
        {
            for (int i = 0; i < a-1; i++)
            {
                for (int j = k - 5; j >= b[i]; j--)
                {
                    dp[j] = max(dp[j], dp[j - b[i]] + b[i]);
                }
            }
            printf("%d\n", k - dp[k - 5] - b[a - 1]);
        }

    }
}

思路:首先,可以负债,所以我们给费用排序之后取出最贵的用来负债,然后dp。这里唯一要注意的就是反向dp,也就是这里 for (int j = k - 5; j >= b[i]; j--)。为什么不能正向,因为同一种东西不能拿两次。我们假设有一个东西要5块钱,如果正着算,那么dp[5]就会有一个值,然后到了dp[10]的时候,你会等于dp[5]+5,而这时很明显你已经是取了买了这个东西了,但是dp[5]你已经给它买过了,这里就等于5+5.所以就不对了。

换零钱:

#include<iostream>
#include<cstdio>
using namespace std;
 
int a[100005],dp[100005];
int main()
{
    int b[]={1,2,5,10,20,50,100,200,500,1000,2000,5000,10000};
    int n,i,j;
    cin>>n;
    dp[0]=1;
    for(j=0;j<13;j++) {
        for(i=b[j];i<=n;i++)
         dp[i]=( dp[i-b[j]] + dp[i] )%1000000007;
    }
    cout<<dp[n]<<endl;
    return 0;
}

方程设置原因:每一次刷新得到的种类就是 (本身有的钱减去上一次花掉的钱的种类) 加上原有的种类。循环往复。

Adventurer's Guild :

#include<algorithm>
using namespace std;
long long h[2000], s[2002], con[2002],dp[310][310];
int main()
{
    long long a, b, c;
    scanf("%lld%lld%lld", &a, &b, &c);
    for (int i = 1; i <= a; i++)
    {
        scanf("%lld %lld %lld", &h[i], &s[i], &con[i]);
    }
    for (int i = 1; i <= a; i++)
    {
        for (int j = b; j >= h[i]; j--)
        {
            for (int k = c; k >= 0; k--)
            {
                if (s[i] > k)
                {
                    long long f = j + k - s[i];
                    if (f >= h[i])
                    {
                        dp[j][k] = max(dp[j][k], dp[f - h[i]][0] + con[i]);
                    }
                }
                else
                {
                    dp[j][k] = max(dp[j][k], dp[j - h[i]][k - s[i]] + con[i]);
                }
            }
        }
    }
    printf("%lld", dp[b - 1][c]);
}

存在两个量改变:二维背包。注意事项:反向循环,状态转移。且题中要求生命值不为0,所以输出dp[b-1][c]即可。记得long long。

猜你喜欢

转载自blog.csdn.net/YZcheng_plus/article/details/128876032