BZOJ 1032: [JSOI2007]祖碼Zuma 區間DP

just_sort發表於2017-01-19

題目連結:見這裡
解題方法: 區間DP。首先我們把連續相同的珠子都縮在一起 令f[i][j]表示從i開始的j個珠子的最小消除次數 初值 f[i][1]=cnt[i]==1?2:1
然後對於每個區間,我們列舉中間點,拆成兩半求和
如果這個區間兩端點顏色相同,我們還可以把中間消掉,然後兩邊再補射1或0個。
但是這個題目資料是有問題的,按照上面的方法是可以AC,但是有反,具體可以參考下這個部落格:見這裡

程式碼如下:

#include <bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for(int i = a; i <= b; i++)
const int inf = 0x3f3f3f3f;
const int N = 550;
pair <int, int> a[N];
int dp[N][N]; //dp[i][j]從i開始的j個珠子的最小消除次數
int n;
int main(){
    scanf("%d", &n);
    a[0].first = inf;
    int cnt = 0;
    rep(i, 1, n){
        int x;
        scanf("%d", &x);
        if(x != a[cnt].first){
            a[++cnt].first = x;
        }
        a[cnt].second++;
    }
    n = cnt;
    memset(dp, 0x3f, sizeof(dp));
    rep(i, 1, n) dp[i][1] = a[i].second == 1 ? 2 : 1;
    rep(j, 2, n){ //區間長度
        for(int i = 1; i + j - 1 <= n; i++){ //起點
            if(a[i].first == a[i + j - 1].first){
                dp[i][j] = dp[i + 1][j - 2] + (a[i].second + a[i + j - 1].second == 2 ? 1 : 0);
            }
            for(int k = 1; k < j; k++){
                dp[i][j] = min(dp[i][j], dp[i][k] + dp[i + k][j - k]);
            }
        }
    }
    printf("%d\n", dp[1][n]);
    return 0;
}

相關文章