背包DP

P2340 [USACO03FALL] Cow Exhibition G

  • 题意:

N 头奶牛,每头奶牛有智商 S 与情商 F,选出一些奶牛使得它们的情商之和和智商之和大于 0 且情商智商总和最大。

  • 思路:

我们发现,跟状态有关的三个值:S , F , S+F,我们只需要知道其中的两个就可以推出剩下一个,所以,我们可以选其中一个做体积,一个做价值,跑一遍 01背包即可。

#include<bits/stdc++.h>
#define ll long long
#define int long long
using namespace std;
inline ll rd(){
	ll x=0;
	int f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-') f=-1;
		ch=getchar();
	} 
	while(ch>='0'&&ch<='9'){
		x=1ll*x*10+ch-'0';
		ch=getchar();
	}
	return x*f;
}
int n;
struct cow{
	int a,b;
}c[450];
ll sum[1800002];
void init(){
	n=rd();
	for(int i=1;i<=n;i++) c[i].a=rd(),c[i].b=rd();
}
void solve(){
    memset(sum,-0x3f,sizeof sum);
    sum[400000]=0;
	for(int i=1;i<=n;i++){
		if(c[i].a>=0){
            for(int j=800000;j>=c[i].a;j--){
                sum[j]=max(sum[j],sum[j-c[i].a]+c[i].b);
            }
        }
        else{
            for(int j=0;j<=800000+c[i].a;j++){
                sum[j]=max(sum[j],sum[j-c[i].a]+c[i].b);
            }
        }
	} 
}
void print(){
	ll maxx=-1e8;
	for(int i=400000;i<=800000;i++)
        if(sum[i]>=0)
            maxx=max(maxx,sum[i]+i-400000);
	cout<<maxx;
}
signed main(){
	init();
	solve();
	print();
}

P3188 [HNOI2007] 梦幻岛宝珠

  • 题意:

n 颗宝石,选一些宝石使它们总重量不超过 W 且价值和最大,重量 w 不超过 230 且可以表示为 a2b

  • 思路:

一看是 01 背包板子,但问题就出在数据范围,看到 w 可以表示为 a2b 就从这里入手,设 f[i][j] 表示从重量为 k2i 物品 (k 为系数),选出了体积为 j 的物品,但此时我们发现,我们还需要一个数组来帮助我们,于是再定义一个 g 数组,g[i][j] 表示已经从 j2i 从中选取的最大价值,且前 i1 位已经选完。那么我们发现我们可以枚举 p 表示从 2i 里选 p 体积,那么代表剩下的 jp 就到了 2(i1) 这里,就成了 2(jp) ,所以状态转移方程就为:

g[i][j]=max(g[i][j],g[i1][2(jp)+((W>>(i1))&1)]+f[i][p])

关于 ((W>>(i1))&1) 因为 Wi1 位上可能原本为 1 ,那样的话需要加上

#include<bits/stdc++.h>
#define int long long
#define ll long long
using namespace std;
const int N=105;
int n,W;
struct dn{
	int a,b,len,x;
}z[N];
int f[50][12000],g[50][12000];
vector<int> val[51],k[51];
void init(int n){
	memset(f,0,sizeof f);
	memset(g,0,sizeof g);
	for(int i=0;i<=50;i++) val[i].clear(),k[i].clear();
	for(int i=1;i<=n;i++){
		scanf("%d%d",&z[i].a,&z[i].b);
		z[i].len=0;
		while(((z[i].a>>z[i].len)&1)==0){
			z[i].len++;
		}
		z[i].x=z[i].a;
		val[z[i].len].push_back(z[i].b);
		k[z[i].len].push_back((z[i].x>>z[i].len));
	}
	
	int l=0;
	while((W>>l)) l++;
	l--;
	for(int i=0;i<=l;i++){
		if(k[i].size()==0) continue;
		else{
			for(int j=0;j<k[i].size();j++){
				for(int p=1000;p>=k[i][j];p--){
					f[i][p]=max(f[i][p],f[i][p-k[i][j]]+val[i][j]);
				}
			}
		}
	}
	for(int i=0;i<=l;i++){
		for(int j=1000;j>=0;j--){
			for(int p=0;p<=j;p++){
				if(i==0) g[i][j]=max(g[i][j],f[i][p]);
				else{
					g[i][j]=max(g[i][j],g[i-1][(j-p)*2+((W>>(i-1)&1))]+f[i][p]);
				}
			}
		}
	}
	cout<<g[l][1]<<"\n";
}
signed main(){
	while(cin>>n>>W){
		if(n==-1&&W==-1) break; 
		init(n);
	}
} 

P4138 [JOISC2014] 挂饰

  • 题意:

一开始有一个挂钩,现在有 n 个物品,每个物品又有 Ai 个挂钩和 Bi 的喜悦度,现在想要最大化所有挂饰的喜悦值之和。

  • 思路:
    首先按照 Bi 由大到小排个序,把 Ai 当作重量,Bi 当价值,跑遍 01 背包即可
#include<bits/stdc++.h>
using namespace std;
int n;
struct noe{
	int a,b;
}z[4005];
bool cmp(noe x,noe y){
	return x.a>y.a;
}
int f[4003][4003];
signed main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		scanf("%d%d",&z[i].a,&z[i].b);	
	}	
	sort(z+1,z+1+n,cmp);
	for(int i=0;i<=n;i++) f[0][i]=-1e9,f[i][n+1]=-1e9;
	f[0][1]=0;
	for(int i=1;i<=n;i++){
		for(int j=0;j<=n;j++){
			f[i][j]=max(f[i-1][j],f[i-1][max(j-z[i].a,0)+1]+z[i].b);
		}
	}
	int ans=-1e9;
	for(int i=0;i<=n;i++) ans=max(ans,f[n][i]);
	cout<<ans;
}
posted @   yueyan_WZF  阅读(2)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示