题-Knapsack

2020小米选拔赛2-H题(背包问题)

算法:dp优化。
主要解决的问题:一个背包装下的物品价值和最大。
背包最大承受量m,每个物品都有重量和对应的价值。
怎么装才能使得背包价值最大?
题目链接
反思:课后补题,没做出来,题目做少了。
题意:

多组输入,每组n个物品,m的容量。
求背包价值最大。

思路:测试数据到了1e5级别了,复杂度高,那么就要对动态规划优化
主要算法:常规动态规划,时间复杂度(o(n*m));

for(int i=1;i<=n;i++){
	for(int j=m;j>=a[i].weight;j--){
	//	错误代码,每次在添加a[i].value都是独立的,而下面重复。
	//dp[j-b]=max(dp[j-b],dp[j]+a[i].value);
   	// 多思考思考为什么是这样。
		dp[j]=max(dp[j],dp[j-a[i].weight]+a[i].value);
	}
}

如何优化的呢(下面的代码其实是一种不充分的证明,还不够严谨)
dp优化:时间复杂度就在o(500m)之内了。
题解:代码如下

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
int read(){
    ll s = 0, f = 1; char ch = getchar();
    while(!isdigit(ch)){
        if(ch == '-') f = -1;
        ch = getchar();
    }
    while(isdigit(ch)) s = (s << 3) + (s << 1) + (ch ^ 48), ch = getchar();
    return s * f;
}

struct zw{
	ll weight;
	ll value;
}a[200010];
bool cmp(zw x,zw y){
	return x.value*y.weight>y.value*x.weight;
}
ll dp[200010];
int main (){
	int n,m;
	while(cin>>n>>m){
		for(int i=0;i<=m;i++) dp[i]=0;
		for(int i=1;i<=n;i++){
			a[i].weight=read();
			a[i].value=read();
		}
		//对value/weight 的大小排个序。 比值大的放前面。
		sort(a+1,a+1+n,cmp);
		//for(int i=1;i<=n;i++)cout<<a[i].value<<" "<<a[i].weight<<endl;
		ll sum=0;
		ll index=1;
		/*使用dp前的优化
		 m>500 其实就是一种不充分的归纳,聚集吧,当然也可写成m>200,
		但不建议写成m>1000或者大于更大,毕竟while循环主要目的减小m的值,
		以减小时间复杂度
		*/
		while(m>500&&index<=n){
			m-=a[index].weight;
			sum+=a[index].value;
			index++; 
		}     ///ÒÉ»óµã¡£ 
		    ll ans2=0;
		 for(int i=index;i<=n;i++){
		 	for(int j=m;j>=a[i].weight;j--){ 
			 //向下递减
		 		ll b=a[i].weight;
		 		//´错误代码
				 //dp[j-b]=max(dp[j-b],dp[j]+a[i].value); 
		 		dp[j]=max(dp[j],dp[j-b]+a[i].value);
		 	    //ans2=max(dp[j],ans2);
				 //没有覆盖,相互独立。
			 }
			 //for(int i=0;i<=m;i++)cout<<dp[i]<<" ";	   cout<<endl;
		 }
		 cout<<sum+dp[m]<<endl;
	}
}```


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

axtices

谢谢您的打赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值