UVA10163
这道题需要两次dp
1. 求最小安全指数最大值
定义:
$dp[i][j]$为考虑前i个人看守前j个仓库最小安全指数最大值,$SafetyIndex[i]$为第$i$个人的能力值。
初始化:
$dp[i][0]=inf$(常数/0=无穷大)
剩下的$dp=0$
转移方程:
其中$x$为前$i$个人看守前$x$个仓库,而剩下的$j-x$个仓库由第$i$个人看守。
这样,$dp[M][N]$就是所求答案。
2. 求此时的最小花费
定义:
$dp[i][j]$为考虑前$i$个人看守前$j$个仓库并满足求出的安全指数条件的最小花费
初始化:
$dp[0][i]=inf$
剩下的dp元素=0
转移方程:
AC代码
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 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
| #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];
bool Input() { cin >> N >> M; if (!N && !M) { return false; } for (int i = 1; i <= M; ++i) { cin >> SafetyIndex[i]; } return true; } void 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 << ' '; if (!Min) { cout << 0 << endl; return; } 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; }
|
每次的$dp[i]$都只用到$dp[i-1]$,所以可以滚动优化降一维,过了那就算了吧233333。