Codeforces 730J:Bottles(背包dp)

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 }
原文地址:https://www.cnblogs.com/fightfordream/p/6400278.html