[CFの1218C]ジャンピングトランスフォーマー

問題の意味

あなたは欲しい((0,0)\)\行きました\((N - 1、M - 1)\) 右または下)は、いくつかの点でいくつかの点でいくつかの障害があるかもしれない、と定期的にこれらの障害のサンプルビート:
\の[(X、Y)\ RIGHTARROW(X + D、Y - D)\ RIGHTARROW(X + D、Y)\ RIGHTARROW(X、Y + D)\ RIGHTARROW(X、Y) ... \]
前記\((x、y)は\ ) の障害に現れる点の位置であり、\(D \)は、各拍動のパラメータです。
たび、それを破壊するために特定の価格を過ごすための障壁があり、そしてそれは表示されません。
最小コストを過ごすために探しています。
\(N、M \のLeq 500 \)、\ (1当量500000 \ \障害の数)

問題の解決策

Dpが実際には、これは非常に奇妙です。シンプルなDPは、この質問を解決していないので、第二の出会いで同じ障害物が過剰な貢献を生成します。
便宜のために、我々は、周期と各障害物をスキップ\(0、1、2、3 \)マッピングを確立:
[(X、Y)を\ \ RIGHTARROW 0 \\(X + D、Y - D)\ RIGHTARROW 1 \\(X + D、
Y)\ RIGHTARROW 2 \\(X、Y + D)\ RIGHTARROW 3 \\ \] 特定の決定された時間に、ことに注意\(T \) 場所(\を( X、Y)\)\(X + Yの\)の値が決定されます。
このプロパティは遭遇同じ障害物がないことを意味し、非常に重要である\(<0,1> \)状態、が同じ状態\(<2,3> \)
性質に応じて、定期的にパスをジャンプ、ほとんどが二度同じ状態を経験しました。
ことができる過剰生成する状態の寄与を考える(<0,2> \)\ \ (<1,2> \)、\ (<0,3> \)を、また、障害物は、一定の条件が満たされました。
順番に遭遇障害物だけでなく、計算よりなり事前確率寄与確率事前あろう、この制限を除去「異なる時間に現れる」します。
このように、我々は接頭辞アレイを事前にすることができます\(S [0/1] [I]、[J] \) を表し\((i、j)は\ ) 寄与の同じ行の合計の左側に/上同一の列に発生し得る障害物の位置を。
設定考える\(dp_ {I、J} \) を表し\((i、j)は\ ) 最小コストを。
:同じライン転送
\ \ [dp_ {I、J} =分\ {。。 - K、J} + S_ {1、I、J} - S_ {1、I - - K、J} DLT \ dp_ {I}を]
\(DLT \)貢献ダブルカウントです。この寄与は、することができた(<0,2> \)\この状態が生成されます。このことは、取り扱いがより困難でした。
ポイントの状態を考える((iはK、J - \ )\) ポイント\((i、j)は\ ) 満たさなければならない不要な寄与を生じる
(X、J)\ [\を RIGHTARROW 0 \\(X + D、J)\ RIGHTARROW 2 \\
X \ GEQ私は\とX + D \当量I + K \] 直接の規制を移動し、接頭辞がうまくやるこの事。
同じ列が似て転送します。
まだ詳細の多くは、特定の処理コードを参照してください。
時間計算\(\ mathcal O(N ^ 3)\) 空間的複雑\(\ mathcal O(^ N-2)\)

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N = 505;
typedef pair <int, int> pii;
int n, m, k;
ll dp[N][N], sum[N][N], s[2][N][N], d[2][N][N];
vector <pii> c[2][N][N];
bool add (int x, int y, int t, int e) {
    if (x + y - 2 >= t && t % 4 == (x + y - 2) % 4) {
        return sum[x][y] += e, 1;
    } else {
        return 0;
    }
}
int main () {
    scanf("%d%d%d", &n, &m, &k);
    for (int i = 1, x, y, d, t, e; i <= k; ++i) {
        scanf("%d%d%d%d%d", &x, &y, &d, &t, &e), ++x, ++y;
        if (add(x, y, t, e)) {
            if (d % 4 == 3) {
                c[0][x][y + d].push_back(make_pair(d, e));
            }
            if (d % 4 == 2) {
                c[1][x + d][y].push_back(make_pair(d, e));
            }
        }
        if (add(x + d, y - d, t + 1, e)) {
            if (d % 4 == 1) {
                c[0][x + d][y].push_back(make_pair(d, e));
            }
        }
        add(x + d, y, t + 2, e);
        add(x, y + d, t + 3, e);
    }
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m; ++j) {
            s[0][i][j] = s[0][i][j - 1] + sum[i][j];
            s[1][i][j] = s[1][i - 1][j] + sum[i][j];
        }
    }
    for (int i = 1; i <= n; ++i) {
        dp[i][0] = 1ll << 60;
    }
    for (int j = 1; j <= m; ++j) {
        dp[0][j] = 1ll << 60;
    }
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m; ++j) {
            if (i == 1 && j == 1) {
                dp[i][j] = sum[i][j];
                continue;
            } else {
                dp[i][j] = 1ll << 60;
            }
            for (pii p : c[0][i][j]) {
                d[0][i][j - p.first] += p.second;
            }
            for (pii p : c[1][i][j]) {
                d[1][i - p.first][j] += p.second;
            }
            ll vx = 0, vy = 0;
            for (int k = 1; k < j; ++k) {
                vx += d[0][i][j - k];
                dp[i][j] = min(dp[i][j], dp[i][j - k] + s[0][i][j] - s[0][i][j - k] - vx);
            }
            for (int k = 1; k < i; ++k) {
                vy += d[1][i - k][j];
                dp[i][j] = min(dp[i][j], dp[i - k][j] + s[1][i][j] - s[1][i - k][j] - vy);
            }
        }
    }
    printf("%lld\n", dp[n][m]);
    return 0;
}

おすすめ

転載: www.cnblogs.com/psimonw/p/11612405.html