羅区P2365のタスクスケジューリング(最適化されたスロープDP)

ポータル

アイデア:
最も単純な公式dpが良いと:みましょう\(DP(i、j)は \) 正面を示す\(私は\)タスクの合計\(J \)最小コストのバッチを。
次に、伝達方程式がある:
[DP(I、J)=分\ {DP(K、J-1)+(J * sumT_i + S)*(sumC_i sumC_k-)\} \] \
理由\(S * Jの\) バッチの裏には、影響を受けた答えの前に開始されますので。
しかし、分析の複雑さがある\(O(N ^ 3) \) 、確かではありません。
第二の状態のために、なぜ必要性を考えてみましょうか?後者は、全状態が数回を開始しました知らないので、後の効果を排除するためです。
しかし、我々は置くことができ、事前に算出したコストを、一度起動し、その後、後続のすべてのマシンが貢献するために、我々はこの貢献は忘れ進め、あなたがされ、この問題で、バックアップすることができた後、効果解消を余儀なくさを
従って変換\(DP \)のように式:
[DP(I)=分\ {DP(J)+ sumT_i *(sumC_i-sumC_j)+ S×(sumC_n-sum_j)\} \] \
実際には、この羅は、データの谷をしてきたが、十分なされていません!我々はまた、最適化することができます。
観察\(DP \)の部分に続く式、\(I、Jの\)製品フォーム関連の変数ので、私たちは斜面DPの最適化を検討することができます。\(I、Jの\)変数の分離がある:\ [DP(J)=(S + sumT_i)* + dp_i sumC_j sumC_i-S-sumT_iは* sumC_n \]明らかに、スロープと直接この式は、連続的にキューを維持凸包に増加しました。それの時間複雑です\(O(n)と\)



#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 5005, MOD = 1e9 + 7;
int n, s;
int sumt[N], sumc[N];
int q[N], dp[N];
int main() {
#ifdef heyuhhh
    freopen("input.in", "r", stdin);
#else
    ios::sync_with_stdio(false); cin.tie(0);
#endif
    cin >> n >> s;
    for(int i = 1; i <= n; i++) {
        int t, c; cin >> t >> c;
        sumt[i] = sumt[i - 1] + t;
        sumc[i] = sumc[i - 1] + c;
    }
    int l = 1, r = 1; q[1] = 0;
    for(int i = 1; i <= n; i++) {
        while(l < r && dp[q[l + 1]] - dp[q[l]] <= (s + sumt[i]) * (sumc[q[l + 1]] - sumc[q[l]])) ++l;
        dp[i] = dp[q[l]] - sumt[i] * sumc[q[l]] - s * sumc[q[l]] + sumt[i] * sumc[i] + s * sumc[n];
        while(l < r && (dp[i] - dp[q[r]]) * (sumc[q[r]] - sumc[q[r - 1]]) <= (dp[q[r]] - dp[q[r - 1]]) * (sumc[i] - sumc[q[r]])) --r;
        q[++r] = i;
    }
    cout << dp[n];
    return 0;
}

おすすめ

転載: www.cnblogs.com/heyuhhh/p/11415406.html