完全背包及其延申

1、最经典的完全背包
有n种食物。每种食物含有的热量和带来的幸福感分别为a[i]和b[i]。一个人每天摄入的热量不超过m。
求在不超过一天热量摄入量前提下,可获得的最多幸福感是多少。

这是一道最简单的完全背包题,没什么好说的,我们直接套公式就可以了。

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
int dp[100006];
int main()
{
    int t;
    while(cin>>n)
    {
        memset(dp,0,sizeof(dp));
        int i,j,m;
        int a[105],b[105];
        for(i = 0; i<t; i++)
            cin>>a[i]>>b[i];
      cin>>m;
        for(i = 0; i<n; i++) 
        {
            for(j = a[i]; j<=m; j++)
            {
                dp[j] = max(dp[j],dp[j-a[i]]+b[i]);//状态转移方程
            }
        }
        cout<<dp[m]<<endl;
     }
     return 0;
}

2、完全背包求方案数(整数划分)
题目:给出两个数n,m。m代表求出的n的划分中最大值不能超过m。比如n=5,m=3。则用1,2,3这三个数去分割5。求方案数。
下面首先介绍一下整数划分:
f(n,m)代表求不超过m的n的划分数。
f(n,m)=1;n=1或m=1
f(n,m)=f(n,n);n<m
f(n,m)=f(n,m-1);n==m
f(n,m)=f(n-m,m)+f(n,m-1);n>m选m或不选m

对于一般的整数划分数,我们只需要按完全背包的套路来。但是这个题n的范围是1000,m的范围是100,最后求出的划分数明显大于10^18,所以这里需要修改一下状态转移方程。
一般整数划分状态转移方程:dp[n]=dp[n]+dp[n-m];n的划分数等于含n的划分数与不含n的划分数之和。二维的方程为:dp[m][n]=dp[m-1][n]+dp[m][n-m];
对于这道题的状态转移方程:a[n]+=a[n-m]; a[n]%=INF;求10^18前面的数。
b[j]+=b[j-i]+(a[j]+a[j-i])/INF;求10^18后面的数。最后如果划分数大于INF,结果为两者之和,否则为a[n]。

#include <iostream>
#include <cmath>
#include <stdio.h>
#include <vector>
#include <algorithm>
#include<cstring>
#define ll 0x3f3f3f
using namespace std;

long long INF,a[1010],b[1010];//a储存10^18以内的数,b储存10^18之后的数

int main()
{
    int n,k;
    INF=1;
    for(int i=0; i<18; i++)
        INF*=10;
   cin>>n>>k;
        memset(b,0,sizeof(b));
        memset(a,0,sizeof(a));
        a[0]=1;

        for(int i=1; i<=k; i++)
        {
            for(int j=i; j<=n; j++)
            {
                b[j]+=b[j-i]+(a[j]+a[j-i])/INF;
                a[j]+=a[j-i];
                a[j]%=INF;
            }
        }
        if(b[n])
           cout<<b[n];
        cout<<a[n]<<endl;

    return 0;
}

通过上面代码,有一个问题,我们初始化时为什么要让a[0]=1呢???是不是代表0的划分数是1呢???如果m的是不是从一开始的,会不会还是a[0]=1呢???
答案是肯定的,这里的a[0]=1代表的不是说0的划分数是1,而是对第一轮的数据进行初始化,不管m是从及开始,初始化时都要让a[0]=1。对第一轮的数据初始化代表的是从m的初始值到n都只用m的初始值去划分,有几种划分数,显然,划分数只能是0或1。说到这,我有不得不说打表了,如果实在理解不了,就去打表,打完表一切就都清晰了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值