HDU 6076 (動態規劃)

HDU 6076 Security Check

Problem :
有兩個長度爲n的隊列過安檢,每一個人有一個特徵值。若是兩個隊列中的第一我的的特徵值之差小於等於k,那麼一次只能檢查其中一我的,不然一次能夠檢查兩我的。每次檢查花費1的世時間。問最後檢查完全部人以後所須要的時間。(n <= 60000, k <= 10)(3s時限)
Solution :
容易想到一個dp方程,dp[i][j]表示當前檢查到a隊列第i我的,b隊列第j我的。
dp[i][j] = dp[i - 1][j - 1] + 1 ( abs(a[i] - b[j] > k)
dp[i][j] = min(dp[i - 1][j] + dp[i][j - 1]) + 1 ( abs(a[i] - b[j] <= k)
從二維平面的角度考慮,每一個點的決策至關因而從左、下、左下三個方向轉移過來。
注意到 k<=10,即在多數狀況下狀態由左下方轉移過來,少數點來自於左或下。
所以能夠對於每一個對角線維護一個dp值,對於每一個須要從左或下轉移的關鍵點進行處理。其狀態能夠由下方或者左方對應的對角線上的狀態轉移過來。
最後若終點不是關鍵點,特殊處理一下。php

#include <iostream>
#include <algorithm>

using namespace std;

const int INF = 1e8 + 7;
const int N = 600008;
int dp[N << 1], f[N << 1];
int a[N], b[N], ref[N];
int sol[N];
int n, k;

void init()
{
    cin >> n >> k;
    for (int i = 1; i <= n; ++i) cin >> a[i];
    for (int j = 1; j <= n; ++j)
    {
        cin >> b[j];
        ref[b[j]] = j;
    }
}
void solve()
{

    for (int i = - n - 1; i <= n + 1; ++i) dp[i + N] = INF;
    for (int i = 0; i <= n; ++i)
        dp[i + N] = i, f[i + N] = 0;
    for (int i = 0; i <= n; ++i)
        dp[-i + N] = i, f[-i + N] = i;
    for (int i = 1; i <= n; ++i)
    {
        int tot = 0;
        for (int j = a[i] - k; j <= a[i] + k; ++j)
        {
            if (j <= 0) continue;
            if (j > n) continue;
            sol[++tot] = ref[j];
        }
        sort(sol + 1, sol + tot + 1);
        for (int j = 1; j <= tot; ++j)
        {
            int tmp = sol[j] - i + N;
            dp[tmp] = min(dp[tmp + 1] + i - 1 - f[tmp + 1] + 1, dp[tmp - 1] + i - f[tmp - 1] + 1);
            f[tmp] = i;
        }
    }
    if (abs(a[n] - b[n]) > k) dp[N] = dp[N] + n - f[N];
    cout << dp[N] << endl;
}
int main()
{
    cin.sync_with_stdio(0);
    int T; cin >> T;
    while (T--)
    {
        init();
        solve();
    }
}
相關文章
相關標籤/搜索