UVA10163
这道题需要两次dp
1. 求最小安全指数最大值
定义:
为考虑前i个人看守前j个仓库最小安全指数最大值,
为第
个人的能力值。
初始化:
(常数/0=无穷大)
剩下的
转移方程:
其中
为前
个人看守前
个仓库,而剩下的
个仓库由第
个人看守。
这样,
就是所求答案。
2. 求此时的最小花费
定义:
为考虑前
个人看守前
个仓库并满足求出的安全指数条件的最小花费
初始化:
剩下的dp元素=0
转移方程:
AC代码
#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cmath>
#include<map>
using namespace std;
constexpr static int inf = 0x3f3f3f3f;
int N, M;
int SafetyIndex[31];
int dp[31][101];
//考虑前i个人看守前j个仓库最小安全指数最大值
bool Input() {
cin >> N >> M;
if (!N && !M) {
return false;
}
for (int i = 1; i <= M; ++i) {
cin >> SafetyIndex[i];
}
return true;
}
void DP() {
//第一次dp
for (int i = 0; i <= M; ++i) {
dp[i][0] = inf;
}
for (int i = 1; i <= M; ++i) {
for (int j = 1; j <= N; ++j) {
dp[i][j] = dp[i - 1][j];
for (int x = 0; x < j; ++x) {
dp[i][j] = max(dp[i][j], min(dp[i - 1][x], SafetyIndex[i] / (j - x)));
}
}
}
int Min = dp[M][N];
cout << Min << ' ';
//如果安全指数为0,则谁都不雇佣最便宜
if (!Min) {
cout << 0 << endl;
return;
}
//第二次dp
memset(dp, 0x0, sizeof(dp));
for (int i = 1; i <= N; i++) {
dp[0][i] = inf;
}
for (int i = 1; i <= M; ++i) {
for (int j = 1; j <= N; ++j) {
dp[i][j] = dp[i - 1][j];
for (int x = 0; x < j; ++x) {
if (SafetyIndex[i] / (j - x) >= Min) {
dp[i][j] = min(dp[i][j], dp[i - 1][x] + SafetyIndex[i]);
}
}
}
}
cout << dp[M][N] << endl;
}
int main() {
while (Input()) {
memset(dp, 0x0, sizeof(dp));
DP();
}
return 0;
}
每次的 都只用到 ,所以可以滚动优化降一维,过了那就算了吧233333。