【动态规划:入门】背包DP

文档:背包九讲

混合背包(01、多重、完全)

洛谷P1833 樱花
题意:有n种物品,每种拿一个都消耗 T i T_i Ti。有的只能拿一个,有的最多拿 a i a_i ai个,有的可以拿无数个(每种物品可拿 P i P_i Pi次)。每种物品的价值是 c i c_i ci,背包容量是 T T T,求能获得的最大价值。
图

思路:

这题就是01背包+多重背包+完全背包。

代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=10000;
int dp[1003];//前:第几种物品 后:所装多少 
int t[maxn+2],c[maxn+2],p[maxn+2];
int m;//全局变量:总时间(背包容量) 
void completepack(int i,int cost,int weight){
	for(int j=0;j<=m;j++){
		if(j>=cost)dp[j]=max(dp[j],dp[j-cost]+weight);
	}
}
void zeroonepack(int i,int cost,int weight){ // 倒序枚举
	for(int j=m;j>=0;j--){
		if(j>=cost)
		dp[j]=max(dp[j],dp[j-cost]+weight);
	}
}
void multiplepack(int i,int cost,int weight,int amount){
	if(cost*amount>=m){
		completepack(i,cost,weight);
		return;
	}
	int k=1;
	while(k<amount){
		zeroonepack(i,k*cost,k*weight);
		amount-=k;
		k*=2;
	}
	zeroonepack(i,amount*cost,amount*weight);
} 
int main(){
	int h1,m1,h2,m2,n;
	scanf("%d:%d %d:%d %d",&h1,&m1,&h2,&m2,&n);
	for(int i=1;i<=n;i++)scanf("%d%d%d",&t[i],&c[i],&p[i]);
	int mx=m2-m1;
	int hx=(h2-h1)*60;
	if(mx<0)hx=(h2-h1-1)*60;
	if(mx<0)mx=60-m1+m2;
	m=hx+mx;
	for(int i=1;i<=n;i++){
		if(p[i]==0)completepack(i,t[i],c[i]);
		else multiplepack(i,t[i],c[i],p[i]);
	}
	printf("%d\n",dp[m]);
}

分组背包

bitset优化
牛客:简单瞎搞题

#include<bits/stdc++.h>
using namespace std;
const int maxn = 103;
int l[maxn],r[maxn];
bitset<maxn*maxn*maxn>dp[2];
// 01背包:一个物品放一次
// 多重背包:一个物品放a[i]次
// 完全背包:一个物品放无限次
// 当前:多个物品放一次
int main(){
    int n;cin>>n;
    for(int i=1;i<=n;++i) scanf("%d%d",&l[i],&r[i]);
    int flg=0;
    // bitset要处理第一对
    for(int i=l[1];i<=r[1];++i) dp[flg].set(i*i);
    for(int i=2;i<=n;++i){
        flg^=1;
        dp[flg].reset();
        for(int k=l[i];k<=r[i];++k){
            dp[flg] |= dp[flg^1]<<(k*k);
            /*
            其实等价于
            for(int j=1;j<=(1e2)^3;++j){
            	if(j>=k*k && dp[flg][j-k*k]) dp[flg][j] = 1;
            }
            */
        }
    }
    cout<<dp[flg].count()<<endl;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值