DP(两次) UVA 10163 Storage Keepers

题目传送门

 1 /*
 2    题意:(我懒得写,照搬网上的)有n个仓库,m个人看管。一个仓库只能由一个人来看管,一个人可以看管多个仓库。
 3         每个人有一个能力值pi,如果他看管k个仓库,那么所看管的每个仓库的安全值为 pi/k(向下取整)
 4         如果某个仓库没有人看管,那么它的安全值为0。所有仓库的安全值L = min{ 每个仓库的安全值 }
 5         从m个人中选择一些人雇佣,问所有仓库的安全值最高是多少,在安全值最高的情况下,求雇佣(能力值)的最少价钱。
 6     DP(两次):dp[i][j]表示前i个人管理j个仓库的最大安全值,那么dp[i][j] = max (dp[i-1][j-k], p[i] / k) (k是当前选择的仓库数)
 7             在保障最大安全值下选择最小花费,也就是:p[i] / k >= dp[m][n]下,dp2[i][j]表示前i个人管理了j个仓库所需最小花费
 8     这题我想了一上午,同时考虑安全值和花费的最优,结果越弄越乱,依据题意应该安全第一!
 9  */
10 /************************************************
11  * Author        :Running_Time
12  * Created Time  :2015-8-16 9:59:59
13  * File Name     :UVA_10163.cpp
14  ************************************************/
15 
16 #include <cstdio>
17 #include <algorithm>
18 #include <iostream>
19 #include <sstream>
20 #include <cstring>
21 #include <cmath>
22 #include <string>
23 #include <vector>
24 #include <queue>
25 #include <deque>
26 #include <stack>
27 #include <list>
28 #include <map>
29 #include <set>
30 #include <bitset>
31 #include <cstdlib>
32 #include <ctime>
33 using namespace std;
34 
35 #define lson l, mid, rt << 1
36 #define rson mid + 1, r, rt << 1 | 1
37 typedef long long ll;
38 const int MAXN = 1e2 + 10;
39 const int MAXM = 33;
40 const int INF = 0x3f3f3f3f;
41 const int MOD = 1e9 + 7;
42 int dp[MAXM][MAXN], dp2[MAXM][MAXN];
43 int p[MAXM];
44 
45 int main(void)    {     //UVA 10163    Storage Keepers
46     int n, m;
47     while (scanf ("%d%d", &n, &m) == 2) {
48         if (!n && !m)   break;
49         for (int i=1; i<=m; ++i)    scanf ("%d", &p[i]);
50         memset (dp, 0, sizeof (dp));
51         for (int i=1; i<=m; ++i)    {
52             dp[i-1][0] = INF;
53             for (int j=1; j<=n; ++j)    {
54                 dp[i][j] = dp[i-1][j];
55                 for (int k=1; k<=j; ++k)    {
56                     dp[i][j] = max (dp[i][j], min (dp[i-1][j-k], p[i] / k));
57                 }
58             }
59         }
60         memset (dp2, INF, sizeof (dp2));
61         for (int i=1; i<=m; ++i)    {
62             dp2[i-1][0] = 0;
63             for (int j=1; j<=n; ++j)    {
64                 dp2[i][j] = dp2[i-1][j];
65                 for (int k=1; k<=j; ++k)    {
66                     int s = p[i] / k;
67                     if (s >= dp[m][n])  {
68                         dp2[i][j] = min (dp2[i][j], dp2[i-1][j-k] + p[i]);
69                     }
70                 }
71             }
72         }
73 
74         printf ("%d %d
", dp[m][n], (dp[m][n] == 0) ? 0 : dp2[m][n]);
75     }
76 
77     return 0;
78 }
编译人生,运行世界!
原文地址:https://www.cnblogs.com/Running-Time/p/4734023.html