DP-护卫队(nkoj1006)
题意分析
一个序列,有x和y两种属性, ∑xi ∑ x i 满足一定要求的情况(这里是 ∑xi≤X ∑ x i ≤ X )把序列分组,然后求关于y的极值(这里是Y= ∑ymax ∑ y m a x )
DP
首先定义状态T[i]
为前i辆车通过该桥的最短时间值,根据总时间=前面组的时间+这组的时间
则有
T[i]=min(T[i],T[j]+tmax),其中tmax为该组车所用时间
T
[
i
]
=
m
i
n
(
T
[
i
]
,
T
[
j
]
+
t
m
a
x
)
,
其
中
t
m
a
x
为
该
组
车
所
用
时
间
j可以有两种理解:
- j为上一组最后一辆车,这样j从i-1开始从大到小循环,w_sum在j—之前更新,T[i]在Tmax更新前用T[j]更新
- j为这一组第一辆车,这样j从i开始从大到小循环,w_sum在j—之后更新,T[i]在Tmax更新之后用T[j-1]更新
代码
//
// Created by rv on 2018/5/7.
//
#include <stdio.h>
#include <algorithm>
#define INF_DOUBLE 1E100;
const int MAX_N = 1000 + 5;
int w[MAX_N], s[MAX_N];
double t[MAX_N], T[MAX_N];
int main() {
freopen("data.in", "r", stdin);
int W, L, N;
scanf("%d%d%d", &W, &L, &N);
for (int i = 1; i <= N; i++) { // 听说大部分oi选手从1开始
scanf("%d%d", &w[i], &s[i]);
t[i] = (double) L / s[i];
}
T[0] = 0; // DP初值
for (int i = 1; i <= N; i++) {
T[i] = INF_DOUBLE; // DP初值
long long w_sum = w[i];
double Tmax = t[i];
for (int j = i - 1; j >= 0 && w_sum <= W; w_sum += w[j], j--) {
T[i] = std::min(T[i], T[j] + Tmax);
Tmax = t[j] > Tmax ? t[j] : Tmax;
}
// for (int j = i; j >= 0 && w_sum <= W; j--, w_sum += w[j]) { // 注意w_sum和j的更新顺序和j的初值的关系
// // 注意Tmax和T[i]更新和j的初值的关系
// Tmax = t[j] > Tmax ? t[j] : Tmax;
// T[i] = std::min(T[i], T[j - 1] + Tmax);
// }
// for (int j = 1; j <= N; j++) {
// printf("%lf ", T[j]);
// }
// printf("\n");
}
printf("%.1lf\n", T[N] * 60);
return 0;
}
坑点
int又爆了,以后把int加起来的时候一定要想一下会不会爆!!!