题目:
题目坐标:护卫队.
护卫车队在一条单行的街道前排成一队,前面河上是一座单行的桥。因为街道是一条单行道,所以任何车辆都不能超车。桥能承受一个给定的最大承载量。为了控制桥上的交通,桥两边各站一个指挥员。护卫车队被分成几个组,每组中的车辆都能同时通过该桥。当一组车队达到了桥的另一端,该端的指挥员就用电话通知另一端的指挥员,这样下一组车队才能开始通过该桥。每辆车的重量是已知的。任何一组车队的重量之和不能超过桥的最大承重量。被分在同一组的每一辆车都以其最快的速度通过该桥。一组车队通过该桥的时间是用该车队中速度最慢的车通过该桥所需的时间来表示的。问题要求计算出全部护卫车队通过该桥所需的最短时间值。
输入格式:
第一行包含三个整数,第一个整数表示该桥所能承受的最大载重量(用吨表示);第二个整数表示该桥长度(用千米表示);第三个整数表示该护卫队中车辆的总数( n < 1000 n<1000 n<1000)。接下来的几行中,每行包含两个正整数 W 和 S(用空格隔开),W 表示该车的重量(用吨表示),S 表示该车过桥能达到的最快速度(用千米/小时表示)。车子的重量和速度是按车子排队等候时的顺序给出的。
输出格式:
输出文件应该是一个实数,四舍五入精确到小数点后1位,表示整个护卫车队通过该桥所需的最短时间(用分钟表示)。
输入输出样例:
100 5 10
40 25
50 20
50 20
70 10
12 50
9 70
49 30
38 25
27 50
19 70
75.0
题解:
状态:dp[i]表示前i个车,经过合理的组合,所得到的最小时间。所以当每枚举到一个i时,只用往前找在合理的情况下选择最小的一组。
状态转移方程:
d
p
[
i
]
=
m
a
x
(
d
p
[
i
]
,
d
p
[
j
−
1
]
+
i
—
j
的
最
小
值
)
dp[i] = max(dp[i], dp[j - 1] + i—j的最小值)
dp[i]=max(dp[i],dp[j−1]+i—j的最小值)
i表示前i辆车,
d
p
[
j
−
1
]
+
i
—
j
的
最
小
值
dp[j - 1] + i—j的最小值
dp[j−1]+i—j的最小值 表示前i辆车,将i—j分成一组的时间值。
注意一组的时间值即为每一组最慢车的时间。
还有就是我们可以预先处理一个前i辆车重量的前缀数组,然后每次对于i,j求一个区间重量判断是否合理即可。
代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
const int MAXN = 1005, MAXM = 1e5 + 5;
double zd, w[MAXN], s[MAXN], dp[MAXN], f[MAXN][55], m, d[MAXN];
int n;
double q(int l, int r) {
double _max = -0x3f3f3f3f;//因为同样路程时间最大的,速度最慢所以每次取max
for(int i = l;i <= r; i++) _max = max(_max, f[i][0]);
return _max;
}
int main() {
scanf("%lf %lf %d", &zd, &m, &n);
for(int i = 1;i <= n; i++) {
scanf("%lf %lf", &w[i], &s[i]);
dp[i] = double(m / s[i] * 1.0);
f[i][0] = dp[i];
}
for(int i = 1;i <= n; i++) d[i] = d[i - 1] + w[i];
for(int i = 1;i <= n; i++) {
dp[i] += dp[i - 1];
for(int j = i - 1;j >= 1; j--) {
if(d[i] - d[j - 1] <= zd) dp[i] = min(dp[i], dp[j - 1] + q(j, i));
else break;
}
}
printf("%.1lf", dp[n] * 60);//注意最后求的是分钟数
return 0;
}
如果是求区间最大我们不难想到ST.。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
const int MAXN = 1005, MAXM = 1e5 + 5;
double zd, w[MAXN], s[MAXN], dp[MAXN], f[MAXN][55], m, d[MAXN];
int n;
void ST(double n) {
int k = log(n) / log(2) + 1;
for(int j = 1;j < k; j++) {
for(int i = 1;i <= n - (1 << j) + 1; i++) {
f[i][j] = max(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
}
}
}
double STF(int l, int r) {
int k = log(r - l + 1) / log(2);
return max(f[l][k], f[r - (1 << k) + 1][k]);
}
int main() {
scanf("%lf %lf %d", &zd, &m, &n);
for(int i = 1;i <= n; i++) {
scanf("%lf %lf", &w[i], &s[i]);
dp[i] = double(m / s[i] * 1.0);
f[i][0] = dp[i];
}
ST(n);
for(int i = 1;i <= n; i++) d[i] = d[i - 1] + w[i];
for(int i = 1;i <= n; i++) {
dp[i] += dp[i - 1];
for(int j = i - 1;j >= 1; j--) {
if(d[i] - d[j - 1] <= zd) dp[i] = min(dp[i], dp[j - 1] + STF(j, i));
else break;
}
}
printf("%.1lf", dp[n] * 60);
return 0;
}