UVA 10163 - Storage Keepers
公司有N(1 ≤ N ≤ 100)个仓库,需要安保。现在有M(1 ≤ M ≤ 30)个人应聘职位,每个人有个值P[i] (1 ≤ P[i] ≤ 1000);安排第i个人看守k个仓库,则这k个仓库的安全值是 ⌊p[i]k⌋≥s ,并且花费为Pi。公司要保证所有仓库的最小安全值尽可能的大,求解这个值并且求这个方案的最小花费。
dp[i][j]:表示安排前i个人看守j个仓库能获得的最大的安全值。
考虑第i个人看守了k个仓库,那么前i-1个人需要看守j-k个仓库的最大安全值为dp[i-1][j-k],而后k个仓库的安全值是 ⌊p[i]k⌋≥s 。
dp[i][j] = max(dp[i-1][j], min(dp[i-1][j-k], ⌊p[i]k⌋≥s );
由此可以得到最大安全值为s;
要在安全值 >= s的情况下找到最小的花费。
dq[i][j]:表示安排前i个人看守j个仓库在最大的安全值s下的最小花费。
转移同上:
考虑第i个人看守了k个仓库,那么前i-1个人需要看守j-k个仓库的安全值下的花费为dp[i-1][j-k],而后k个仓库的安全值s下的花费是p[i]。当然(
⌊p[i]k⌋≥s
)
dq[i][j] = min(dq[i-1][j], dp[i-1][j-k] + p[i]);
/*
直接对dp数组路径还原的话总会有一两组数据出错233333
*/
#include <bits/stdc++.h>
using namespace std;
const int INF = 999999999;
int n, m;
int p[350];
int dp[350][1050];
int dq[350][1050];
int main () {
for (; scanf ("%d%d", &n, &m) == 2; ) {
if (n == m && m == 0) break;
for (int i=1; i<=m; i++) {
scanf ("%d", &p[i]);
}
memset(dq, 0, sizeof(dq));
memset(dp, 0, sizeof(dp));
for (int i=1; i<=n; i++) {
dp[1][i] = p[1] / i;
dp[i][0] = INF;
}
for (int i=2; i<=m; i++) {
dp[i][1] = max(dp[i-1][1], p[i]);
for (int j=2; j<=n; j++) {
dp[i][j] = dp[i-1][j];
for (int k=1; k<=p[i] && k<=j; k++) {
dp[i][j] = max(dp[i][j], min(dp[i-1][j-k], p[i]/k));
}
}
}
int ans = dp[m][n];
for (int i=1; i<=n; i++) {
if (p[1]/i >= ans) dq[1][i] = p[1];
else dq[1][i] = INF;
}
for (int i=2; i<=m; i++) {
dq[i][1] = dq[i-1][1];
if (p[i]>=ans) dq[i][1] = min(dq[i-1][1], p[i]);
for (int j=2; j<=n; j++) {
dq[i][j] = dq[i-1][j];
for (int k=1; k<=p[i] && k<=j && p[i]/k >= ans; k++) {
dq[i][j] = min(dq[i][j], dq[i-1][j-k] + p[i]);
}
}
}
if (ans == 0) dq[m][n] = 0;
cout << dp[m][n] << " ";
cout << dq[m][n] << endl;
}
return 0;
}
*/