http://codeforces.com/problemset/problem/730/J
题意:有n个瓶子,每个瓶子有一个当前里面的水量,还有一个瓶子容量,问要把所有的当前水量放到尽量少的瓶子里至少需要几个瓶子,还有最少需要倒的水量(把一个瓶子的水倒到另一个瓶子的总水量)。
思路:是一个背包dp,dp[i][j] 表示选择i个瓶子容量为j的时候当前拥有的最大的水量。不过第三层循环当时不知道应该怎么写。
1 #include <cstdio> 2 #include <cstring> 3 #include <cmath> 4 #include <cstdlib> 5 #include <algorithm> 6 #include <string> 7 #include <iostream> 8 #include <stack> 9 #include <map> 10 #include <queue> 11 #include <set> 12 using namespace std; 13 typedef long long LL; 14 #define N 105 15 #define INF 0x3f3f3f3f 16 struct node { 17 int a, b; 18 } p[N]; 19 int dp[N][N*N]; // dp[i][j] 表示选择i个瓶子容量为j的时候当前拥有的最大的水量 20 bool cmp(const node &a, const node &b) { return a.b > b.b; } 21 int main() 22 { 23 int n, sum = 0, tmp, cnt = 0, tol = 0, ans = 0; 24 scanf("%d", &n); 25 for(int i = 1; i <= n; i++) scanf("%d", &p[i].a), sum += p[i].a; 26 for(int i = 1; i <= n; i++) scanf("%d", &p[i].b), tol += p[i].b; 27 tmp = sum; 28 sort(p + 1, p + 1 + n, cmp); 29 for(int i = 1; i <= n; i++) { 30 tmp -= p[i].b; 31 if(tmp <= 0) { cnt = i; break; } // 确定最终的瓶子数 32 } 33 memset(dp, -1, sizeof(dp)); 34 dp[0][0] = 0; 35 for(int i = 1; i <= n; i++) { 36 for(int j = tol; j >= p[i].b; j--) { // 类似01背包 37 for(int k = i; k > 0; k--) { // 之前选择的状态再加上目前的第i个瓶子能否得到优化,这样就可以枚举所有情况了 38 if(dp[k-1][j-p[i].b] != -1) { // 如果上一个状态有解 39 dp[k][j] = max(dp[k][j], dp[k-1][j-p[i].b] + p[i].a); 40 } 41 } 42 } 43 } 44 for(int i = sum; i <= tol; i++) 45 ans = max(ans, dp[cnt][i]); 46 printf("%d %d ", cnt, sum - ans); 47 return 0; 48 }