Vijos-p1355フリートクロッシングブリッジの問題(動的計画法+ dp)

フリートクロッシングの問題

説明

既存のN台の車両は、片道橋を順番に通過する必要があります。橋が狭すぎるため、2台の車両を並べて通過することはできません。また、小さな橋は長い間建設されてきたため、最大(トン)と記録されている限られた重量しか耐えられません。管理者は、最初の順序でN台の車両をグループに分割し、一度に1つのグループが橋を渡ることを許可し、1つのグループのすべての車両が橋を渡った後でのみ、次のグループの車両が橋を渡ることができます。各車両の重量と最高速度は既知であり、各グループの車両の橋を渡る時間は、グループ内で最も遅い車両によって決定されます。管理者がこれらのN台の車両をグループ化するプログラムを作成して、すべての車両が橋を通過する時間が最短になるように支援してください。

フォーマット

入力フォーマット

ファイルの最初の行には、Max(トン)、Len(ブリッジの長さ、km)、およびN(1つ以上のスペースで区切られている)の3つの数値があります。次に、N行があり、各行に2つの数字があります。i番目の行の2つの数字は、それぞれi番目の車両の重量w(トン)と最高速度v(km / h)を表します。

max、len、w、vは、32ビット符号付き整数型の最大値を超えず、整数n <1000です。

出力フォーマット

ファイルには1行しかありません。つまり、すべての車両が橋を渡る最短時間(分)で、小数点以下1桁まで正確です。

例1

サンプル入力1

100 5 10
40 25
50 20
50 20
70 10
12 50
9 70
49 30
38 25
27 50
19 70

サンプル出力1

75.0

制限

1秒

問題解決

ポータル
質問は順番にグループ化されます。dp[i]
は最初のi車の最適解表します。i番目の車がk台の隣接する車と同時に橋を渡ることができると考えてください。K=(1〜ik + 1)最小値は
dp [i] dp [i] = min(dp [i]、dp [j-1] + a [j、i])の最適解です。a
[j、i]はjを表す同時に橋を渡るi台の車に費やされた時間(前処理と計算が可能)

コード

#include <algorithm>  //车队过桥问题
#include <cstring>
#include <iostream>
using namespace std;
const int maxn = 1002;
int Max, N;
double Len;
int w[maxn], v[maxn];
double dp[maxn];
int minv[maxn * 4];  //线段树, 区间最小值

// 复习线段树
void build(int s, int t, int p) {
    
      //对区间[s, t]建立线段树当前根编号为p
    if (s == t) {
    
    
        minv[p] = v[s];
        return;
    }
    int m = (s + t) / 2;
    build(s, m, p * 2), build(m + 1, t, p * 2 + 1);
    minv[p] = min(minv[p * 2], minv[p * 2 + 1]);
}

int check(int l, int r, int s, int t, int p) {
    
      //查询区间[l, r]的线段树
    if (l <= s && t <= r) return minv[p];
    int m = (s + t) / 2;  //二分是分树, 而不是分查找区间
    if (r <= m) {
    
    
        return check(l, r, s, m, p * 2);
    } else if (m < l) {
    
    
        return check(l, r, m + 1, t, p * 2 + 1);
    } else {
    
    
        return min(check(l, m, s, m, p * 2),
                   check(m + 1, r, m + 1, t, p * 2 + 1));
    }
}

int main() {
    
    
    cin >> Max >> Len >> N;
    for (int i = 1; i <= N; i++) cin >> w[i] >> v[i];
    memset(minv, 0x3f, sizeof(minv));
    build(1, N, 1);

    memset(dp, 0x7f, sizeof(dp));
    dp[0] = 0;
    dp[1] = Len / v[1];

    for (int i = 2; i <= N; i++) {
    
    
        for (int j = i; j >= 1; j--) {
    
      //把区间[j, i]当做一个小队
            long long tot = 0;
            for (int k = j; k <= i; k++) tot += w[k];  //计算区间[j, i]的重量
            if (tot > Max) break;  //如果超重, 以i为最后的计算完毕
            dp[i] = min(dp[i], dp[j - 1] + Len / check(j, i, 1, N, 1));
        }
    }

    printf("%.1f\n", dp[N] * 60);

    system("pause");
    return 0;
}

おすすめ

転載: blog.csdn.net/qq_45349225/article/details/109570310