Time Limit:3s Memory Limit:256MByte
Submissions:220Solved:92
你现在在咸鱼商店,你有M元钱。咸鱼商店有N个物品,每个物品有两个属性,一个是他的价格S[i],另外一个是他的价值V[i]。现在你想买一些物品,使得这些物品的价值和大于等于K,并且使得其中价值最低的商品的价值尽量高。请你输出这个最大价值。
解法1:贪心的策略,既然要总物品价值>=K中价值最低商品的所能达到的最大价值,所以想尽可能先挑价值大的。因此,先对物品的价值
按照从大到小排序,如果价值相同,按照花费从小到大排序。然后进行01背包,直到容量为M的背包所得价值大于等于M,输出该物品的价值。
虽然有好心人告诉我思路,可是我还是停了两天写的。最初有一个困惑想不明白,对于前i件物品,有一个dp[j]代表用容量为j的背包去装前i件
物品所能获得的最大价值,然后最后看dp[M]是否大于等于K,大于等于K输出第i件物品的价值,否则继续考虑将前i+1件物品放入背包,然后
想不通的地方是:对于背包容量M考虑将前i件物品装进去,dp[M]尽管满足要求,我感觉好像不能确定dp[M]所获得的价值到底包不包括第i件
物品的价值(即第i件物品到底装没装进背包)。想到这里非常困惑,不过闲下来好好想了想,想明白了。下面是关键代码:
for(int i = 1; i <= N; i++) //考虑用背包装前i件物品去获得最大价值。
{
for(int j = M; j>= a[i].price; j--)
{
dp[j] = max(dp[j],dp[j-a[i].price]+a[i].value);
}
if(dp[M]>=K)
{
printf("%d\n",a[i].value);
flag = false;
break;
}
}
如果dp[i-a[i].price] + a[i].value > dp[j]。则说明第i件物品(也是最后一件物品,其价值最小)是装入背包了。
但是对于dp[i-a[i].price] + a[i].vale < dp[j]的情况,说明不装第i件物品,那么它的状态还是之前的状态。就是将
前i-1件物品装入容量为j的背包所得的最大价值,如果这种条件满足了>=K。则循环一定在变量循环到i之前就
break掉了。简单说根本就轮不到在考虑把前i件物品放到背包里,前面就已经有满足条件的解了。所以大佬提
供这样的思路特别有道理的。
AC代码:
#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#define inf 0x3f3f3f3f
using namespace std;
const int maxv = 1003;
const int maxn = 1003;
int N,M,K;
int dp[maxv];
struct obj
{
int price; ///价格
int value; ///价值
}a[maxn];
bool cmp(struct obj a,struct obj b)
{
if(a.value == b.value) ///物品a,b价值相同
return a.price<b.price; ///按照价格从小到大排序
else
return a.value>b.value; ///优先按价值排序
}
int main()
{
while(~scanf("%d%d%d",&N,&M,&K))
{
for(int i = 1; i <= N; i++)
scanf("%d%d",&a[i].price,&a[i].value);
sort(a+1,a+N+1,cmp); ///优先选择按价值排序,价值相等按照花费从小到大排序
memset(dp,0,sizeof(dp));
bool flag = true;
for(int i = 1; i <= N; i++)
{
for(int j = M; j>= a[i].price; j--)
{
dp[j] = max(dp[j],dp[j-a[i].price]+a[i].value);
}
if(dp[M]>=K)
{
printf("%d\n",a[i].value);
flag = false;
break;
}
}
if(flag)
printf("-1\n");
}
return 0;
}
思路2:官方题解给出二分+01背包的做法。所求答案无非是一个数,既然是一个数,这个数的范围就是1~inf的一个数,
这个题目给出物品最大价值是1e6,因此二分范围1~1e6即可,对于mid,对价值大于mid的所有物品进行一次01背包,
如果最后dp[M]>=K,让low = mid+1;否则high = mid-1,再次进行二分操作。
#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#define inf 0x3f3f3f3f
using namespace std;
const int maxv = 1003;
const int maxn = 1003;
int N,M,K;
int dp[maxv];
struct obj
{
int price; ///价格
int value; ///价值
}a[maxn];
bool cmp(struct obj a,struct obj b)
{
if(a.value == b.value)
return a.price<b.price;
else
return a.value>b.value;
}
int Calculate_Value(int mid)
{
memset(dp,0,sizeof(dp));
for(int i = 1; i <= N; i++)
{
if(a[i].value>=mid) ///只对价值大于等于mid的物体进行01背包
{
for(int j = M; j >= a[i].price; j--)
{
dp[j] = max(dp[j],dp[j-a[i].price]+a[i].value);
}
if(dp[M]>=K)
return 1;
}
else break;
}
return 0;
}
int main()
{
while(~scanf("%d%d%d",&N,&M,&K))
{
for(int i = 1; i <= N; i++)
scanf("%d%d",&a[i].price,&a[i].value);
sort(a+1,a+1+N,cmp);
int low = 1;
int high = 1e6;
int ans = -1;
while(low<=high)
{
int mid = (low+high)/2;
int flag = Calculate_Value(mid);
if(flag) ///dp[M]>=K
{
low = mid+1;
ans = mid;
}
else
high = mid-1;
}
printf("%d\n",ans);
}
return 0;
}