链接
传送门
题意
有\(n\)个仓库,\(m\)个管理员,每个管理员有一个能力值\(p[i]\),雇佣管理员的花费与能力值相同。一个仓库的安全度为\(p[i]/k\),其中\(k\)为管理员管理仓库的个数,求最小安全度的最大值和此时的花费。
思路
定义状态\(dp[i][j]\)为前\(i\)个管理员管理前\(j\)个仓库时的最小安全度的最大值。有\(dp[i][j]=\max\{\min\left(dp[i-1][j-k],p[i]/k\right)\}\)。求花费的方法与之类似。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| #include <cstdio> #include <cstring> #include <algorithm>
using namespace std;
const int inf = 0x3f3f3f3f; const int maxn = 110;
int p[maxn]; int dp[maxn][maxn];
int main() { int n, m; while (~scanf("%d%d", &n, &m) && (n || m)) { for (int i = 1; i <= m; ++i) { scanf("%d", &p[i]); } memset(dp, 0, sizeof dp); for (int i = 1; i <= m; ++i) { dp[i - 1][0] = inf; for (int j = 1; j <= n; ++j) { dp[i][j] = dp[i - 1][j]; for (int k = 1; k <= j; ++k) { dp[i][j] = max(dp[i][j], min(dp[i - 1][j - k], p[i] / k)); } } } int ans = dp[m][n]; if (ans == 0) { puts("0 0"); continue; } memset(dp, 0x3f, sizeof dp); for (int i = 1; i <= m; ++i) { dp[i - 1][0] = 0; for (int j = 1; j <= n; ++j) { dp[i][j] = dp[i - 1][j]; for (int k = 1; k <= j; ++k) { if (p[i] / k >= ans) { dp[i][j] = min(dp[i][j], dp[i - 1][j - k] + p[i]); } } } } printf("%d %d\n", ans, dp[m][n]); } return 0; }
|