看了很多博客,有以下两种思路:
以kuangbin神为代表:q-p其实就是不更新的范围,不更新的范围从小到大递增时就不会影响后面的DP了。
以很多很多人为代表:对任意两个物品i,j,为了避免上面存在的那种问题,我们可以算出两种顺序所需要的最少金额,若i->j,则至少需要Pi+Qj,若是j->i则至少需要Pj+Qi。如果已知结果是i->j较优的话,则有Pi+Qj<Pj+Qi,即Qi-Pi>Qj-Pj。参考
二。给一定的钱 ,我们的购买方式是 应该先买M最大的物体(M=Q-P),然后依次买第二大、第三大、、、、、
我们已经知道这个购买方式,怎么实现就要用到DP 中的0-1背包的思想了。
dp[c]=max(dp[c],dp[c-p[i]])+v[i]; c 为第c 个物品。这是用一维数组实现01背包。。
dp[c-p[i]] 是指 我们在容量为c 的包中 放了p[i]之后 还能放的物品的价值。
i 从 1 到 n 。 dp[c-p[n]] 是放了 第n个物品后 还能放多少价值的物品。。。所以 P[n] 的M 值应该最大
通俗的说: 这个dp过程 正好是逆向的 。 dp[c-p[i]]是dp[c]的最优子结构。
所以 在DP 的时候我们应该按照 M的值从小到大排序。
也就是说我们应该按照 Q-P 的值 从小到 大排序在 DP 了。。。。没看懂_(:з」∠)_
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=510;
int dp[5010];
int m;
int n;
//肯定要排序,但是如何排序呢?
//比如优先买价值最高的?
struct goods
{
int p;
int q;
int v;
}g[N];
bool cmp(goods a,goods b)
{
return (a.q-a.p)<(b.q-b.p);
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
for(int i=1;i<=n;++i)
{
scanf("%d%d%d",&g[i].p,&g[i].q,&g[i].v);
}
sort(g+1,g+1+n,cmp);
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;++i)
{
for(int j=m;j>=g[i].q;--j)
dp[j]=max(dp[j],dp[j-g[i].p]+g[i].v);
}
printf("%d\n",dp[m]);
}
return 0;
}
hdu 3177 Crixalis's Equipment的题面和上面一题基本上差不多
区别是 Proud Merchants 要求M钱最多能获得多少价值
Crixalis's Equipment要求V空间能否放下所有的Equipment
贪心策略:先搬差值大的
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=510;
int v;
int n;
struct equip
{
int a;
int b;
}e[N];
bool cmp(equip p,equip q)
{
return (p.b-p.a)>(q.b-q.a); //差值大的先考虑
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&v,&n);
for(int i=1;i<=n;++i)
{
scanf("%d%d",&e[i].a,&e[i].b);
}
sort(e+1,e+1+n,cmp);
int flag=1;
for(int i=1;i<=n;++i)
{
if(v>=e[i].b)
{
v-=e[i].a;
}
else
flag=0;
}
if(flag)
printf("Yes\n");
else
printf("No\n");
}
return 0;
}