题目描述
现在你面前有n个物品,编号分别为1,2,3,……,n。你可以在这当中任意选择任意多个物品。其中第i个物品有两个属性Wi和Ri,当你选择了第i个物品后,你就可以获得Wi的收益;但是,你选择该物品以后选择的所有物品的收益都会减少Ri。现在请你求出,该选择哪些物品,并且该以什么样的顺序选取这些物品,才能使得自己获得的收益最大。
注意,收益的减少是会叠加的。比如,你选择了第i个物品,那么你就会获得了Wi的收益;然后你又选择了第j个物品,你又获得了Wj-Ri收益;之后你又选择了第k个物品,你又获得了Wk-Ri-Rj的收益;那么你获得的收益总和为Wi+(Wj-Ri)+(Wk-Ri-Rj)。
输入输出格式
输入格式:
第一行一个正整数n,表示物品的个数。
接下来第2行到第n+1行,每行两个正整数Wi和Ri,含义如题目所述。
输出格式:
输出仅一行,表示最大的收益。
输入输出样例
说明
20%的数据满足:n<=5,0<=Wi,Ri<=1000。
50%的数据满足:n<=15,0<=Wi,Ri<=1000。
100%的数据满足:n<=3000,0<=Wi,Ri<=200000。
样例解释:我们可以选择1号物品,获得了5点收益;之后我们再选择2号物品,获得3-2=1点收益。最后总的收益值为5+1=6。
正解:贪心+DP 100
注意:由于循环是正着来,而转移是倒着来,so :贪心应按照 r (对后面的影响) 从大到小排序,而非从小到大排序
状态转移方程:F[i][j]=max{F[i-1][j],F[i-1][j-1]+w[i]+r[i]*(j-1)}
边界条件:F[1][1]=w[1] (可有可无,if从1开始循环)
#include<bits/stdc++.h> using namespace std; int ans,n,f[3030][3030]; struct node{ int w,r; }mar[3030]; bool cmp(node A,node B){ return A.r>B.r; } int main() { cin>>n; for(int i=1;i<=n;i++) cin>>mar[i].w>>mar[i].r; sort(mar+1,mar+1+n,cmp); for(int i=1;i<=n;i++){ for(int j=1;j<=i;j++){ f[i][j]=max(f[i-1][j],f[i-1][j-1]+mar[i].w-mar[i].r*(j-1));//f[i][j] is i 判断了几个,j 选择了几个 } } for(int i=1;i<=n;i++) ans=ans>f[n][i]?ans:f[n][i]; cout<<ans; return 0; }
暴力:DFS 50
#include<cstdio> #include<cmath> #include<algorithm> #include<cstring> #include<string> #include<vector> #include<stack> #include<iostream> using namespace std; int n,ans,vis[3030]; struct node{ int w,r; }coca[3030]; void init(){ scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d%d",&coca[i].w,&coca[i].r); } void output(){ printf("%d",ans); } void dfs(int sum,int hp,int sh){ ans=ans>hp?ans:hp; if(sum==n) return ; for(int i=1;i<=n;i++){ if(vis[i]==0){ int tp=coca[i].w-sh; if(tp<0) continue; vis[i]=1;sum+=1;hp+=tp;sh+=coca[i].r; dfs(sum,hp,sh); vis[i]=0;sum-=1;hp-=tp;sh-=coca[i].r; } } } void work(){ dfs(0,0,0); } int main() { init(); work(); output(); return 0; }