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;
}
}```