• 题解 P2647 【最大收益】


    身为两个死对头,这题很好地将贪心和 (dp) 结合了起来。

    首先考虑一下买一个东西对之后所有东西的影响。不难发现,当我们所买的东西相同的时候,肯定是先买影响最小物品最划算。所以我们要 排序

    现在,我们就把问题转化为了:

    如何买一堆物品,每个物品有一个价值,且价值取决于之后所购买的物品的数量,使得总价值最大。
    

    不妨设 (dp_{i,j}) 表示在从后往前(i) 个物品这里,买了 (j) 个物品的最大收益。而如果我们倒着转移,会有些不方便(不习惯)。于是,把排序反一下,大的排在前面,然后设当前第 (i) 个物品为最早买的就好啦。

    至于 (dp) 方程,考虑买与不买两种情况。

    1. 对于买的情况,我们的价值没有变。(dp_{i,j} = dp_{i-1,j})
    2. 对于不买的情况,考虑价值的变化量。 (dp_{i,j-1} = dp_{i-1,j-1} + w_i - p_i * j)
    3. 边界:(dp_{1,1} = w_1),即只买第一个物品。

    综合起来取 (max) 就好啦!

    #include <bits/stdc++.h>
    using namespace std;
    #define N 3010
    #define ll long long
    
    template <class T>
    inline void read(T& a){
    	T x = 0, s = 1;
    	char c = getchar();
    	while(!isdigit(c)){ if(c == '-') s = -1; c = getchar(); }
    	while(isdigit(c)){ x = x * 10 + (c ^ '0'); c = getchar(); }
    	a = x * s;
    	return ;
    }
    
    int dp[N][N]; 
    int w[N], p[N]; 
    int n; 
    int ans = 0; 
    
    struct node{
    	int w, p; 
    	
    	bool operator < (const node& a) const{
    		return p > a.p; 
    	}
    } a[N];
    
    int main(){
    	read(n);
    	for(int i = 1; i <= n; i++)
    		read(a[i].w), read(a[i].p); 
    	sort(a + 1, a + n + 1); 
    	dp[1][1] = a[1].w; 
    	for(int i = 2; i <= n; i++){
    		for(int j = 0; j <= i; j++){
    			if(j) dp[i][j] = max(dp[i][j], dp[i-1][j-1] + a[i].w- a[i].p * (j - 1));   // 买第 i 个 
    			dp[i][j] = max(dp[i][j], dp[i-1][j]); 
    		}	
    	}
    	for(int i = 1; i <= n; i++)
    		ans = max(ans, dp[n][i]); 
    	cout << ans << endl;
    	return 0; 
    }
    
  • 相关阅读:
    ps_基于2020的官方教程
    杂记_好玩的
    linux _文件目录与权限
    levelDb笔记
    《好学的C++ 第2版》 第9章 一些高级编程技术
    《好学的C++ 第2版》 第8章 文件-电子存储
    《好学的C++ 第2版》 第7章 字符串--分析文本
    《好学的C++ 第2版》 第6章 指针--我知道数据在哪里
    《好学的C++ 第2版》 第5章 数组--都给我排好队
    《好学的C++ 第2版》 第4章 函数--分工与合作
  • 原文地址:https://www.cnblogs.com/wondering-world/p/14066567.html
Copyright © 2020-2023  润新知