UVA10163
这道题需要两次dp
1. 求最小安全指数最大值
定义:
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]为考虑前i个人看守前j个仓库最小安全指数最大值,
S
a
f
e
t
y
I
n
d
e
x
[
i
]
SafetyIndex[i]
SafetyIndex[i]为第
i
i
i个人的能力值。
初始化:
d
p
[
i
]
[
0
]
=
i
n
f
dp[i][0]=inf
dp[i][0]=inf(常数/0=无穷大)
剩下的
d
p
=
0
dp=0
dp=0
转移方程:
d
p
[
i
]
[
j
]
=
m
a
x
(
d
p
[
i
]
[
j
]
,
m
i
n
(
d
p
[
i
−
1
]
[
x
]
,
S
a
f
e
t
y
I
n
d
e
x
[
i
]
/
(
j
−
x
)
)
)
,
(
0
≤
x
<
j
)
dp[i][j]=max(dp[i][j], min(dp[i - 1][x], SafetyIndex[i] / (j - x))),(0\leq x<j)
dp[i][j]=max(dp[i][j],min(dp[i−1][x],SafetyIndex[i]/(j−x))),(0≤x<j)
其中
x
x
x为前
i
i
i个人看守前
x
x
x个仓库,而剩下的
j
−
x
j-x
j−x个仓库由第
i
i
i个人看守。
这样,
d
p
[
M
]
[
N
]
dp[M][N]
dp[M][N]就是所求答案。
2. 求此时的最小花费
定义:
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]为考虑前
i
i
i个人看守前
j
j
j个仓库并满足求出的安全指数条件的最小花费
初始化:
d
p
[
0
]
[
i
]
=
i
n
f
dp[0][i]=inf
dp[0][i]=inf
剩下的dp元素=0
转移方程:
i
f
(
S
a
f
e
t
y
I
n
d
e
x
[
i
]
/
(
j
−
x
)
>
=
上
一
问
求
出
的
结
果
)
d
p
[
i
]
[
j
]
=
m
i
n
(
d
p
[
i
]
[
j
]
,
d
p
[
i
−
1
]
[
x
]
+
S
a
f
e
t
y
I
n
d
e
x
[
i
]
)
if(SafetyIndex[i] / (j - x) >= 上一问求出的结果)\\dp[i][j] = min(dp[i][j], dp[i - 1][x] + SafetyIndex[i])
if(SafetyIndex[i]/(j−x)>=上一问求出的结果)dp[i][j]=min(dp[i][j],dp[i−1][x]+SafetyIndex[i])
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;
}
每次的 d p [ i ] dp[i] dp[i]都只用到 d p [ i − 1 ] dp[i-1] dp[i−1],所以可以滚动优化降一维,过了那就算了吧233333。