DP-护卫队(nkoj1006)

DP-护卫队(nkoj1006)

题意分析

一个序列,有x和y两种属性, x i 满足一定要求的情况(这里是 x i X )把序列分组,然后求关于y的极值(这里是Y= y m a x )

DP

首先定义状态T[i]为前i辆车通过该桥的最短时间值,根据总时间=前面组的时间+这组的时间则有

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加起来的时候一定要想一下会不会爆!!!

猜你喜欢

转载自blog.csdn.net/xenoncat/article/details/80220504