Blocks POJ - 1390 多维dp

题意:有一排box,各有不同的颜色。你可以通过点击某个box使得与其相邻的同色box全部消掉,然后你可以得到的分数为消去长度的平方,问怎样得到最高分?

题解:考虑用一维dp,/*dp[i]为1~i个block(我们称颜色相同的一段box为一个block)所能得到的最大得分*/发现无法递推。

   考虑用二维dp,dp[i][j]为从block i 到 block j 的最大得分

      考虑最右端的j1.直接消除j

            2。它和左边的某个block合并:dp[i][k-1]+dp[k+1][j-1]+(len[k]+len[j])^2

   发现无法计算,因为合并一块以后还能继续合并,可能得到更优解。

   所以用三维dp dp[i][j][extra_len] 代表从block i 到block j ,且将j右边长为extra_len的box与 bolck j 合并时(也就是说其颜色与j相同)能取得的最大值。

代码:

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<cstring>
#include<queue>
#include<string.h>
#include<algorithm>
using namespace std;
const int maxn = 200;
struct block {
    int color;
    int len;
}segment[maxn];
int score[maxn][maxn][maxn];
int click_box(int start, int end, int extra_len) {
    int i, res, temp;
    int &now = score[start][end][extra_len];
    if (now> 0)return now;//记忆递归
    res = segment[end].len + extra_len;
    res *= res;
    if (start == end) { return now = res;}//递归边界
    res += click_box(start, end - 1, 0);//直接消掉extra_len+end
    for (i = end - 1; i >= start; i--) {
        if (segment[i].color != segment[end].color)continue;
        temp = click_box(start, i, segment[end].len + extra_len)+click_box(i+1,end-1,0);//找到前面某个i 一起消掉
        if (temp <= res)continue;
        res = temp;
    }
    now = res;
    return now;
}
int main() {
    int t, n, i, j, end, color;
    cin >> t;
    for (int i = 1; i <= t; i++) {
        cin >> n; end = 0;
        cin >> segment[end].color;
        segment[end].len = 1;
        for (j = 1; j < n; j++) {
            cin >> color;
            if (color == segment[end].color)segment[end].len++;
            else end++, segment[end].color = color, segment[end].len = 1;
        }
        memset(score, 0, sizeof(score));
        cout << "Case " << i << ": " << click_box(0, end, 0) << endl;
    }
    system("pause");
    //return 0;
}

 

posted @ 2018-04-11 14:59  SuuTTT  阅读(172)  评论(0编辑  收藏  举报