ZOJ 3211 Dream City DP 01背包 经典问题
题目大意:JAVAMAN 到梦幻城市旅游见到了黄金树,黄金树上每天回结出金子。已经有n棵树,JAVAMAN要停留m天,每天只能砍掉一棵树,砍掉树后就能得到树上的黄金。给定n棵树上原有的黄金a[i]和每天可以新增加的黄金b[i],求他最多可以得到多少黄金。中途如果有1天不砍树的话,之后的日子久不能砍树,所有最好每天都砍树,或者直到树被砍完。
这个其实是个背包问题,把日期看成背包的容量。然后n棵树当成n个物品。
假设我们取得由某 m 棵树组成的最优解。如果先砍的树的b值比后砍的树的b值大,
那么我们总能交换这两树砍的顺序而得到更多的钱。所以我们按增加钱币量b值升序将n棵树排序。
然后就是个dp 的过程,dp[i][j] 表示 在前 j 天,前 i 颗树 能达到的最大效益
Source Code:
//#pragma comment(linker, "/STACK:16777216") //for c++ Compiler #include <stdio.h> #include <iostream> #include <fstream> #include <cstring> #include <cmath> #include <stack> #include <string> #include <map> #include <set> #include <list> #include <queue> #include <vector> #include <algorithm> #define Max(a,b) (((a) > (b)) ? (a) : (b)) #define Min(a,b) (((a) < (b)) ? (a) : (b)) #define Abs(x) (((x) > 0) ? (x) : (-(x))) #define MOD 1000000007 #define pi acos(-1.0) using namespace std; typedef long long ll ; typedef unsigned long long ull ; typedef unsigned int uint ; typedef unsigned char uchar ; template<class T> inline void checkmin(T &a,T b){if(a>b) a=b;} template<class T> inline void checkmax(T &a,T b){if(a<b) a=b;} const double eps = 1e-7 ; const int N = 210 ; const int M = 1100011*2 ; const ll P = 10000000097ll ; const int MAXN = 10900000 ; const int INF = 0x3f3f3f3f ; const int offset = 100 ; int n, m; int dp[300][300]; //dp[i][j] 意思是在前j天,前i颗树 能达到的最大效益 struct sc { int a, b; } a[300]; bool cmp (struct sc a, struct sc b) { return a.b < b.b; } int main() { std::ios::sync_with_stdio(false); int i, j, t, k, u, c, v, p, numCase = 0; cin >> t; while (t--) { cin >> n >> m; for (i = 1; i <= n; ++i) cin >> a[i].a; for (i = 1; i <= n; ++i) cin >> a[i].b; sort (a + 1, a + 1 + n, cmp); memset (dp, 0, sizeof (dp)); for (i = 1; i <= n; ++i) { for (j = 1; j <= m; ++j) { dp[i][j] = Max (dp[i - 1][j], dp[i - 1][j - 1] + a[i].a + (j - 1) * a[i].b); //Choose or not choose } } cout << dp[n][m] << endl; } return 0; }