输入:
5
4 4
1 1
5 2
5 5
4 3
输出:
10
解题思路:这个题一看很容易就会想到01背包DP,dp[i][j]表示从前i个物品中选,总重量为j的最大价值是多少,具体转移方程如下:
首先对于所有的j初始化:dp[i][j]=dp[i-1][j]
当前物品的重量w,价值v满足,v>=j时,dp[i][j+w]=max(dp[i][j+w],dp[i-1][j]+v)
然后就是排序问题,这是本题最主要的难点了(个人认为)。如果有两个物品i和j,i能放在j的上面,j却不能放在i的上面,此时这样的排列顺序是最优的,其应该满足如下关系式:
wi+sum<=vj
wj+sum>vi(sum为除了物品i,j之外的所有物品的重量和)
可得:wi<=vj,vi<wj
于是可以得到排序条件是wi+vi<wj+vj
上代码:
#include <bits/stdc++.h>
using namespace std;
const int N=1010;
struct node{
int v;
int w;
}p[N];
int n,dp[N][N*20];
bool cmp(node a,node b)
{
return a.w+a.v<b.w+b.v;
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
scanf("%d%d",&p[i].w,&p[i].v);
sort(p+1,p+1+n,cmp);
for(int i=1;i<=n;i++)
{
for(int j=0;j<=n*20;j++)
dp[i][j]=dp[i-1][j];
for(int j=p[i].v;j>=0;j--)
dp[i][j+p[i].w]=max(dp[i][j+p[i].w],dp[i-1][j]+p[i].v);
}
int ans=-1;
for(int i=n*20;i>=0;i--)
ans=max(ans,dp[n][i]);
cout<<ans<<endl;
return 0;
}