基础背包

Posted zjl192628928

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基础背包相关的知识,希望对你有一定的参考价值。

hdu 3033 分组背包

题目大意:总共有n双鞋,每个鞋子有个牌子,有k种牌子,每种牌子至少买一双鞋子。每双鞋子有一定的消费跟价值。求用m多的钱买最多价值的鞋。

解题思路:这题和分组背包有点不一样,从每组至多一个变成了每组至少一个,多加个if语句就可以了

#include<iostream>
#include<cstring>
#include<vector>
#include<cmath>
using namespace std;
typedef long long ll;
const int maxn=10005;
int N,V,M,K,dp[20][maxn],value[maxn],num[maxn],weight[maxn];
struct node{
    int cost,val;
    node(int a,int b){
        cost=a;
        val=b;
    }
};
int main(){
    while(cin>>N>>M>>K){
        for(int i=1;i<=20;i++)vec[i].clear();
        memset(dp,-1,sizeof(dp));
        for(int i=0;i<=M;i++)dp[0][i]=0;
        for(int i=1;i<=N;i++){
            int x,y,z;
            cin>>x>>y>>z;
            vec[x].push_back(node(y,z));
        }
        for(int i=1;i<=K;i++){
            for(int j=0;j<vec[i].size();j++){
                for(int k=M;k>=vec[i][j].cost;k--){
                    if(dp[i][k-vec[i][j].cost]!=-1) //非第一次取第i组 
                    dp[i][k]=max(dp[i][k],dp[i][k-vec[i][j].cost]+vec[i][j].val);
                    if(dp[i-1][k-vec[i][j].cost]!=-1) //第一次取第i组 
                    dp[i][k]=max(dp[i][k],dp[i-1][k-vec[i][j].cost]+vec[i][j].val);
                    //不能调换两个if的顺序因为如果第一个在上面则两个都会执行,重复计算 
                }
            }
        }
        if(dp[K][M]<0)puts("Impossible");
        else cout<<dp[K][M]<<endl;
    }
    return 0;
}

 

hdu 2191 多重背包

 

Input

输入数据首先包含一个正整数C,表示有C组测试用例,每组测试用例的第一行是两个整数n和m(1<=n<=100, 1<=m<=100),分别表示经费的金额和大米的种类,然后是m行数据,每行包含3个数p,h和c(1<=p<=20,1<=h<=200,1<=c<=20),分别表示每袋的价格、每袋的重量以及对应种类大米的袋数。

Output

对于每组测试数据,请输出能够购买大米的最多重量,你可以假设经费买不光所有的大米,并且经费你可以不用完。每个实例的输出占一行。

解题思路:多重背包,无坑

#include<iostream>
#include<cstring>
#include<vector>
#include<cmath>
using namespace std;
typedef long long ll;
const int maxn=10005;
int n,V,M,K,dp[maxn],value[maxn],num[maxn],weight[maxn];
int main(){
    int T;
    cin>>T;
    while(T--){
        cin>>V>>n;
        for(int i=1;i<=n;i++)
        cin>>weight[i]>>value[i]>>num[i];
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=n;i++){
            if(weight[i]*num[i]>V){
                for(int j=weight[i];j<=V;j++)
                dp[j]=max(dp[j],dp[j-weight[i]]+value[i]);
            }else{
                for(int j=1;j<=num[i];j*=2){
                    for(int k=V;k>=j*weight[i];k--)
                        dp[k]=max(dp[k],dp[k-j*weight[i]]+j*value[i]);
                    num[i]-=j;
                }
                if(num[i]){
                    for(int k=V;k>=num[i]*weight[i];k--)
                    dp[k]=max(dp[k],dp[k-num[i]*weight[i]]+num[i]*value[i]);
                }
            }
        }
        cout<<dp[V]<<endl;
    }
    return 0;
}

 

hdu 3721 多重背包

我们都知道英语是非常重要的,所以阿惠努力做到这一点,以便学习更多的英语单词。为了知道这个词有它的价值和书写的复杂性(每个词的长度不超过10个,只用小写字母),阿辉写下的复杂度总和小于或等于C问题:ahui可以得到的最大值。注意:输入的单词将不相同

输入

每个测试用例的第一行是两个整数n,c,表示ahui的单词数和所写单词的总复杂性。(1≤N≤100000,1≤C≤10000)

接下来的n行中的每一行都是一个字符串和两个整数,表示单词、值(vi)和复杂性(ci)。(0≤vi,Ci≤10)

产量

为每个测试用例在一行中输出最大值。

解题思路:由于N的范围很大,所以我们用01背包去做肯定是会超时的,再看vi和ci都很像最大为10,我们把vi和ci都相同的看成同一个单词,最多就121种,计算每种的数量,再跑多重背包就可以了。

#include<iostream>
#include<cstring>
#include<vector>
#include<cmath>
using namespace std;
typedef long long ll;
const int maxn=100005;
int n,V,M,K,dp[maxn],value[maxn],num[15][15],weight[maxn];
int main(){
    while(~scanf("%d%d",&n,&V)){
        memset(num,0,sizeof(num));
        int sum=0;
        for(int i=1;i<=n;i++){
            char s[105];
            getchar();
            int x,y;
            scanf("%s %d %d",s,&x,&y);
            if(num[x][y]==0){
                sum++;
                value[sum]=x;
                weight[sum]=y;
                num[x][y]++;
                //cout<<x<<" "<<y<<" "<<num[x][y]<<endl;
            }else num[x][y]++;
        }
        n=sum;
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=n;i++){
            //cout<<value[i]<<" "<<weight[i]<<" "<<num[value[i]][weight[i]]<<endl;
            if(num[value[i]][weight[i]]*weight[i]>V){
                for(int j=weight[i];j<=V;j++)
                dp[j]=max(dp[j],dp[j-weight[i]]+value[i]);
            }else{
                for(int j=1;j<=num[value[i]][weight[i]];j*=2){
                    for(int k=V;k>=j*weight[i];k--)
                        dp[k]=max(dp[k],dp[k-j*weight[i]]+j*value[i]);
                    num[value[i]][weight[i]]-=j;
                }
                if(num[value[i]][weight[i]]){
                    int cnt=num[value[i]][weight[i]];
                    for(int k=V;k>=cnt*weight[i];k--)
                    dp[k]=max(dp[k],dp[k-cnt*weight[i]]+cnt*value[i]);
                }
            }
        }
        printf("%d
",dp[V]);
    }
    return 0;
}

 

hdu 1712 分组背包

Acboy这个学期有n门课程,他计划最多花m天学习。当然,他将从不同的课程中获得的利润取决于他花在这门课程上的天数。如何安排m天学习n门课程,以使利润最大化?             

输入  

输入由多个数据集组成。一个数据集以包含两个正整数n和m的一行开始,n是课程数,m是acboy的天数。

接下来,按照矩阵a[i][j],(1<=i<=n<=100,1<=j<=m<=100)。a[i][j]表示如果acboy在课程上花费j天,他将获得价值a[i][j]的利润。

n=0,m=0结束输入。

产量

对于每个数据集,程序应该输出一行,其中包含acboy将获得的最大利润数。

解题思路:分组背包模板

#include<iostream>
#include<cstring>
#include<vector>
#include<cmath>
using namespace std;
typedef long long ll;
const int maxn=100005;
int n,V,m,K,dp[maxn],value[105][105],num[15][15],weight[maxn];
int main(){
    while(cin>>n>>m){
        if(n+m==0)break;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                cin>>value[i][j];
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=n;i++)
            for(int k=m;k>=1;k--)  //注意第二个循环和第三个循环不可调换顺序 
                for(int j=1;j<=m;j++)
                if(k-j>=0)    dp[k]=max(dp[k],dp[k-j]+value[i][j]);
        cout<<dp[m]<<endl;
    }
    return 0;
}

 

hdu 2955 01背包

题目大意:给出抢劫n个银行所能得到的价值及风险,问风险在p以内可抢劫的最大价值

解题思路: 由于被抓的概率都为浮点数,不可作为背包的容量,所以我们只能用价值来做背包的容量,还有一个点就是,我们很难求被抓的概率,所以我们转化成求他不被抓的概率,我们计算它最后的逃跑概率是否大于1-p的最大值即为答案。

#include<iostream>
#include<cstring>
#include<vector>
#include<cmath>
using namespace std;
typedef long long ll;
const int maxn=100005;
int n,m,V,K,value[maxn],num[15][15];
double p,weight[maxn],dp[maxn];
int main(){
    int T;
    cin>>T;
    while(T--){
        cin>>p>>n;
        V=0;
        for(int i=1;i<=n;i++){
            cin>>value[i]>>weight[i];
            V+=value[i];
        }
        memset(dp,0,sizeof(dp));
        dp[0]=1; //抢劫0元逃跑的概率为1 
        for(int i=1;i<=n;i++)
            for(int j=V;j>=value[i];j--)
                dp[j]=max(dp[j],dp[j-value[i]]*(1-weight[i]));
        for(int i=V;i>=0;i--){
            if(dp[i]>=1-p){
                cout<<i<<endl;
                break;
            }
        }
    } 
    return 0;
}

 

以上是关于基础背包的主要内容,如果未能解决你的问题,请参考以下文章

防止导航到同一个片段

动态规划问题3--多重背包

动态规划问题3--多重背包

使用喷气背包导航将自定义过渡动画添加到底部导航设置

[vscode]--HTML代码片段(基础版,reactvuejquery)

背包问题