01背包专题

01背包专题

解析

状态转移方程: f [ i ] [ j ] = m a x ( f [ i − 1 ] [ j ] , f [ i − 1 ] [ j − w [ i ] ] + v [ i ] ) f[i][j]=max(f[i−1][j],f[i−1][j−w[i]]+v[i]) f[i][j]=max(f[i1][j],f[i1][jw[i]]+v[i])
优化:
1,可以优化到一维,但要倒序枚举
2,常数优化
前面的代码中有 f o r ( j = V . . . w [ i ] ) for(j=V...w[i]) for(j=V...w[i]),还可以将这个循环的下限进行改进。
由于只需要最后 f [ j ] f[j] f[j]的值,倒推前一个物品,其实只要知道 f [ j − w [ n ] ] f[j−w[n]] f[jw[n]]即可。以此类推,对以第 j j j个背包,其实只需要知道到 f [ j − s u m w [ j . . . n ] ] f[j−sumw[j...n]] f[jsumw[j...n]]即可,即代码可以改成

for (int i = 1; i <= n; i++) {
    int bound = max(V - sum{w[i]...w[n]}, w[i]);
    for (int j = V; j >= bound, j--)
        f[j] = max(f[j], f[j - w[i]] + v[i]);
}

T1 HDU2602

题解

01背包板子

代码
#include<bits/stdc++.h>
#define M 10009
using namespace std;
int read(){
	int f=1,re=0;
	char ch;
	for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());
	if(ch=='-'){f=-1,ch=getchar();}
	for(;isdigit(ch);ch=getchar()) re=(re<<3)+(re<<1)+ch-'0';
	return re*f;
}
int t,n,m,ans,v[M],w[M],f[M];
int main(){
	t=read();
	while(t--){
		memset(f,0,sizeof(f));
		n=read(),m=read(),ans=0;
		for(int i=1;i<=n;i++) v[i]=read();
		for(int i=1;i<=n;i++) w[i]=read();
		for(int i=1;i<=n;i++)
		 	for(int j=m;j>=w[i];j--)
				f[j]=max(f[j],f[j-w[i]]+v[i]);
		for(int i=0;i<=m;i++) ans=max(ans,f[i]);
		printf("%d\n",ans);
	}return 0;
} 

T2 HDU3466

题解

先排序,再01背包
显然物品本身的价格和他的限制的差值越小,越应该放在前面

代码
#include<bits/stdc++.h>
#define M 10009
using namespace std;
int read(){
	int f=1,re=0;
	char ch;
	for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());
	if(ch=='-'){f=-1,ch=getchar();}
	for(;isdigit(ch);ch=getchar()) re=(re<<3)+(re<<1)+ch-'0';
	return re*f;
}
int n,m,ans,f[M];
struct zb{int x,y,z;}a[M];
bool cmp(const zb &a,const zb &b){return a.y-a.x<b.y-b.x;}
int main(){
	while(~scanf("%d%d",&n,&m)){
		ans=0;
		memset(f,0,sizeof(f));
		for(int i=1;i<=n;i++) a[i].x=read(),a[i].y=read(),a[i].z=read();
		sort(a+1,a+n+1,cmp);
		for(int i=1;i<=n;i++)
			for(int j=m;j>=max(a[i].y,a[i].x);j--)
				f[j]=max(f[j],f[j-a[i].x]+a[i].z);
		for(int i=0;i<=m;i++) ans=max(f[i],ans);
		printf("%d\n",ans);
	}return 0;
} 

T3 HDU2546

题解

贪心的思想,用最后五元钱买最贵的东西,剩下的钱做01背包

代码
#include<bits/stdc++.h>
#define M 10009
using namespace std;
int read(){
	int f=1,re=0;
	char ch;
	for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());
	if(ch=='-'){f=-1,ch=getchar();}
	for(;isdigit(ch);ch=getchar()) re=(re<<3)+(re<<1)+ch-'0';
	return re*f;
}
int f[M],a[M],ans,n,m;
int main(){
	while(scanf("%d",&n)&&n){
		memset(f,0,sizeof(f)),ans=0;
		for(int i=1;i<=n;i++) a[i]=read();
		sort(a+1,a+n+1),m=read();
		if(m<5){printf("%d\n",m);continue;}
		for(int i=1;i<n;i++)
			for(int j=m-5;j>=a[i];j--){
				f[j]=max(f[j],f[j-a[i]]+a[i]);
			}for(int i=0;i<=m-5;i++) ans=max(f[i],ans);
		printf("%d\n",m-ans-a[n]);
	}return 0;
}

T4 HDU1203

题解

逆向思维,计算不被选中的概率

代码
#include<bits/stdc++.h>
#define M 10009
using namespace std;
int read(){
	int f=1,re=0;
	char ch;
	for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());
	if(ch=='-'){f=-1,ch=getchar();}
	for(;isdigit(ch);ch=getchar()) re=(re<<3)+(re<<1)+ch-'0';
	return re*f;
}
int n,m,a[M];
double b[M],f[M],ans;
int main(){
	while(scanf("%d%d",&m,&n)){
		if(!m&&!n) break;ans=1;
		for(int i=0;i<=m;i++) f[i]=1;
		for(int i=1;i<=n;i++) a[i]=read(),scanf("%lf",&b[i]);
		for(int i=1;i<=n;i++)
			for(int j=m;j>=a[i];j--){
				f[j]=min(f[j],f[j-a[i]]*(1-b[i]));
			}for(int i=0;i<=m;i++) ans=min(f[i],ans);
		printf("%.1lf%%\n",(1-ans)*100);
	}return 0;
}

T5 CH5201

题解

01背包,计算方案数

代码
#include<bits/stdc++.h>
#define M 100009
using namespace std;
int read(){
	int f=1,re=0;
	char ch;
	for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());
	if(ch=='-'){f=-1,ch=getchar();}
	for(;isdigit(ch);ch=getchar()) re=(re<<3)+(re<<1)+ch-'0';
	return re*f;
}
int n,m,a[M],f[M];
int main(){
	n=read(),m=read();f[0]=1;
	for(int i=1;i<=n;i++) a[i]=read();
	for(int i=1;i<=n;i++)
		for(int j=m;j>=a[i];j--)
			f[j]+=f[j-a[i]];
	printf("%d\n",f[m]);
	return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值