暑假集训(三种背包问题)

第一种,0-1背包    :

            0-1背包大多解决的的问题时,给你一个容量为V的背包,给你n个物品以及每个物品的价值和重量,每个物品中有一个。

让你在不超出背包容量的情况下尽可以装价值更大的东西。(刚开始可以用二维dp数组来写,也可以优化为以为数组节约空间)。

二维dp解法: 

#include <iostream>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<deque>
#include<queue>
#include<vector>
#include<stack>
#include<ctime>
using namespace std;
#define eps 1e-10
#define INF 0x3f3f3f3f
typedef long long LL;
int main()
{
    LL dp[1000][1000],n,m,v[1000],c[1000];
    memset(dp,0,sizeof(0));
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        cin>>v[i];
    for(int i=1;i<=n;i++)
        cin>>c[i];
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<c[i];j++)
            dp[i][j]=dp[i-1][j];
        for(int j=c[i];j<=m;j++)
            dp[i][j]=max(dp[i-1][j],dp[i-1][j-c[i]]+v[i]);
    }
    for(int i=1;i<=n;i++)//输出背包大小不超过输入容量下的能装的最大价值
    {
        for(int j=0;j<=m;j++)
            cout<<dp[i][j]<<" ";
        cout<<endl;
    }


}

             

优化为一维数组: 

#include <iostream>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<deque>
#include<queue>
#include<vector>
#include<stack>
#include<ctime>
using namespace std;
#define eps 1e-10
#define INF 0x3f3f3f3f
typedef long long LL;
int main()
{
    LL dp[1000],n,m,v[1000],c[1000];
    memset(dp,0,sizeof(0));
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        cin>>v[i];
    for(int i=1;i<=n;i++)
        cin>>c[i];
    for(int i=1;i<=n;i++)
    {
        for(int j=m;j>=c[i];j--)
        dp[j]=max(dp[j],dp[j-c[i]]+v[i]);
        for(int j=0;j<=m;j++)
            cout<<dp[j]<<" ";
        cout<<endl;
    }


}

第二种,完全背包:

           完全被包与0-1背包的区别就是完全背包里的物品数量是无限个,完全背包与0-1背包代码实现相差不大

dp数组正着更新是完全背包,倒着更新是0-1背包;

#include <iostream>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<deque>
#include<queue>
#include<vector>
#include<stack>
#include<ctime>
using namespace std;
#define eps 1e-10
#define INF 0x3f3f3f3f
typedef long long LL;
int main()
{
    LL dp[1000],n,m,v[1000],c[1000];
    memset(dp,0,sizeof(0));
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        cin>>v[i];
    for(int i=1;i<=n;i++)
        cin>>c[i];
    for(int i=1;i<=n;i++)
    {
        for(int j=c[i];j<=m;j--)
        dp[j]=max(dp[j],dp[j-c[i]]+v[i]);
        for(int j=0;j<=m;j++)
            cout<<dp[j]<<" ";
        cout<<endl;
    }


}

第三种,多重背包:

          多重背包就是背包里物品数量不为一但是有限,相当于介于0-1背包与完全背包之间,一般解决多重背包问题把

0-1背包与完全背包结合起来使用,而且一般0-1背包可以用二进制压缩来优化,降低时间复杂度

#include <iostream>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<deque>
#include<queue>
#include<vector>
#include<stack>
#include<ctime>
using namespace std;
#define eps 1e-10
#define INF 0x3f3f3f3f
typedef long long LL;
int v[1005];
int d[1005];
int dp[100005];
int n,m;
void zero(int v)
{
     for(int i=m;i>=v;i--)
        {
            dp[i]=max(dp[i],dp[i-v]+v);

        }
}
void complete(int v)
{
     for(int i=v;i<=m;i++)
        {
            dp[i]=max(dp[i],dp[i-v]+v);

        }
}
void f(int v,int d)
{
    if(v*d>=m)
        complete(v);//完全背包
    else
    {
        int k=1;
        while(k<=d)
        {
            zero(k*v);//0-1背包
            d-=k;
            k*=2;//二进制优化
        }
        zero(v*d);
    }
}
int main()
{
    while((cin>>n>>m)&&(n||m))
    {
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=m;i++)
            dp[i]=-INF;
        for(int i=1;i<=n;i++)
            cin>>v[i];
        for(int i=1;i<=n;i++)
            cin>>d[i];
        for(int i=1;i<=n;i++)
            f(v[i],d[i]);
        int ans=0;
        for(int i=1;i<=m;i++)
            if(dp[i]>0)
                ans++;
            cout<<ans<<endl;
    }
}

这里贴一个例题:https://vjudge.net/contest/239441#problem/B

                                                                B - Coins

Whuacmers use coins.They have coins of value A1,A2,A3...An Silverland dollar. One day Hibix opened purse and found there were some coins. He decided to buy a very nice watch in a nearby shop. He wanted to pay the exact price(without change) and he known the price would not more than m.But he didn't know the exact price of the watch.

You are to write a program which reads n,m,A1,A2,A3...An and C1,C2,C3...Cn corresponding to the number of Tony's coins of value A1,A2,A3...An then calculate how many prices(form 1 to m) Tony can pay use these coins.
Input
The input contains several test cases. The first line of each test case contains two integers n(1 ≤ n ≤ 100),m(m ≤ 100000).The second line contains 2n integers, denoting A1,A2,A3...An,C1,C2,C3...Cn (1 ≤ Ai ≤ 100000,1 ≤ Ci ≤ 1000). The last test case is followed by two zeros.
Output
For each test case output the answer on a single line.
Sample Input
3 10
1 2 4 2 1 1
2 5
1 4 2 1
0 0
Sample Output
8
4

猜你喜欢

转载自blog.csdn.net/qq_41232172/article/details/81117683