POJ 1390 Blocks(记忆化搜索+动态规划)

POJ 1390 Blocks

砌块

时限:5000 MS   内存限制:65536K
提交材料共计: 6204   接受: 2563

描述

你们中的一些人可能玩过一个叫做“积木”的游戏。一行有n个块,每个盒子都有一个颜色。这是一个例子:金,银,铜,金。
相应的图片如下:
 
图1
如果一些相邻的盒子都是相同的颜色,并且它左边的盒子(如果它存在)和它的右边的盒子(如果它存在)都是其他颜色的,我们称它为“盒子段”。有四个盒子段。那就是:金,银,铜,金。片段中分别有1,4,3,1方框。

每次您可以单击一个框,然后包含该框的整个段消失。如果这段是由k个方框组成的,你会得到k*k点。例如,如果你点击一个银盒子,银段消失了,你得到4*4=16点。

现在让我们看看下面的图片:
 
图2

第一个是最优的。

在这个游戏的初始状态下,找出你能得到的最高分数。

输入

第一行包含测试数t(1<=t<=15)。每个案例包含两行。第一行包含整数n(1<=n<=200),即框数。第二行包含n个整数,表示每个框的颜色。整数在1~n的范围内。

输出量

对于每个测试用例,打印用例编号和最高可能的分数。

样本输入

2
9
1 2 2 2 2 3 3 3 1
1
1

样本输出

Case 1: 29
Case 2: 1

解题思路:

将连续的若干个方块作为一个“大块”(box_segment) 考虑,假设开始一共有 n个“大块”,编号0到n-1 第i个大块的颜色是 color[i],包含的方块数目,即长度,是len[i]

用click_box(i,j)表示从大块i到大块j这一段消除后所能 得到的最高分,则整个问题就是: click_box(0,n-1)。

要求click_box(i,j)时,考虑最右边的大块j,对它有两种处理方式,要取其优者:

1) 直接消除它,此时能得到最高分就是: click_box(i,j-1) + len[j]*len[j]

2) 期待以后它能和左边的某个同色大块合并,考虑和左边的某个同色大块合并:

左边的同色大块可能有很多个,到底和哪个合并最 好,不知道,只能枚举。假设大块j和左边的大块 k(i<=k<j-1) 合并,此时能得到的最高分是多少呢?

是不是: click_box(i,k-1) + click_box(k+1,j-1) + (len[k]+len[j])

不对! 因为将大块k和大块j合并后,形成的新大块会在最右边。但直接将其消去,未必是最好的,也许它还应该和左边的同色大块合并,才更好

那么上面的dp不可用,需要改变问题的形式

__________________________________________________________________

click_box(i,j,ex_len) 表示: 大块 j 的右边已经有一个长度为ex_len的大块(该大块可能是在合并过程中形成的),且 j 的颜色和ex_len相同,在此情况下所能得到的最高分 。

于是整个问题就是求:click_box(0,n-1,0)

求click_box(i,j,ex_len)时,有两种处理方法取最优者,假设j和ex_len合并后的大块称作 Q

1) 将Q直接消除,这种做法能得到的最高分就是:  click_box(i,j-1,0) + (len[j]+ex_len)2

2) 期待Q以后能和左边的某个同色大块合并。需要枚举可能和Q 合并的大块。假设让大块k和Q合并,则此时能得到的最大分数是:

  click_box(i,k,len[j]+ex_len) + click_box(k+1,j-1,0)

click_box(i,j,ex_len) 递归的终止条件: i == j

代码:

#include<iostream>
#include<cstring>
using namespace std;
#define N 200 + 5
int dp[N][N][N];
struct segMent {
    int len;
    int color;
};
segMent segNum[N];
int clickBox(int i, int j, int len) {
    if(dp[i][j][len] != -1) return dp[i][j][len];
    int result = (segNum[j].len + len)*(segNum[j].len + len);
    if(i == j) return result;
    result += clickBox(i, j-1, 0);
    for(int k = i; k < j; k++) {
        if(segNum[k].color != segNum[j].color) continue;
        int r = clickBox(k+1, j-1, 0) + clickBox(i, k, segNum[j].len + len);
        result = max(result, r);
    }
    dp[i][j][len] = result;
    return result;
}
int main() {
    int T;
    cin >> T;
    for(int t = 1; t <= T; t++) {
        int n;
        cin >> n;
        int last = -1;
        int count = -1;
        memset(dp, -1, sizeof(dp));
        for(int i = 0; i < n; i++) {
            int v;
            cin >> v;
            if(v != last) {
                count++;
                segNum[count].len = 1;
                segNum[count].color = v;
                last = v;
            } else segNum[count].len++;
        }
        cout << "Case " << t << ": " << clickBox(0, count, 0) << endl;
    }
    return 0;
} 

原文地址:https://www.cnblogs.com/kindleheart/p/9492597.html

时间: 2024-10-31 19:04:02

POJ 1390 Blocks(记忆化搜索+动态规划)的相关文章

poj 1390 Blocks (记忆化搜索)

Blocks Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 4318   Accepted: 1745 Description Some of you may have played a game called 'Blocks'. There are n blocks in a row, each box has a color. Here is an example: Gold, Silver, Silver, Sil

[ACM] poj 1088 滑雪 (记忆化搜索DFS)

求n*m网格内矩形的数目[ACM] poj 1088 滑雪 (记忆化搜索DFS),布布扣,bubuko.com

poj 3156 hash+记忆化搜索 期望dp

#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> using namespace std; int n,m; #define N 32 #define mod 10007LL #define mod2 10000007 #define inf 0x3fffffff typedef long long ll; typedef double dd; int f[N]

POJ 4968 DP||记忆化搜索

给出N个人的平局分X 根据GPA规则计算可能的最高平均GPA和最低平均GPA 可以DP预处理出来所有结果  或者记忆化搜索 DP: #include "stdio.h" #include "string.h" int inf=100000000; double a[11][1100],b[11][1100]; double Max(double a,double b) { if (a<b) return b; else return a; } double M

POJ 1088 滑雪(记忆化搜索+dfs)

滑雪 Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 83489   Accepted: 31234 Description Michael喜欢滑雪百这并不奇怪, 因为滑雪的确很刺激.可是为了获得速度,滑的区域必须向下倾斜,而且当你滑到坡底,你不得不再次走上坡或者等待升降机来载你.Michael想知道载一个区域中最长底滑坡.区域由一个二维数组给出.数组的每个数字代表点的高度.下面是一个例子 1 2 3 4 5 16 17

poj 1651 dp 记忆化搜索

题意: 给出n个整数a1,a2,-,an,要求从中取出中间的n-2个数(两端的数不能取),取出每个数的代价为它两边的数和它的乘积,问取出这n-2个数的最小代价为多少? 限制: 3 <= n <= 100; 1 <= ai <= 100 思路: dp 记忆化搜索 对于每个过程其实就是,枚举最后取的数a[i],然后把区间[l,r]分割成[l,i]和[i,r]两部分. dp[l][r]=min(gao(l,i)+a[left]*a[i]*a[right]+gao(i,r))

[BZOJ1032][P1840] 祖玛 记忆化搜索 动态规划

    描述 Description     某天,小x在玩一个经典小游戏--zumo.zumo游戏的规则是,给你一段长度为n的连续的彩色珠子,珠子的颜色不一定完全相同,但是,如果连续相同颜色的珠子大于等于k个,这些珠子就会消失.当然,最初的状态可能不必要直接消掉一些珠子(见样例).现在你有无穷个所有颜色的珠子,并且你可以在任意地方插入珠子.现在提出问题:给你一个固定的状态,你最少需要用多少个小球,才能将所有的小球消去.               输入格式 Input Format     第

POJ 1088 滑雪 记忆化搜索

解析:状态d[i][j]代表r=i , c=j这个位置能滑的最大长度.深搜+备忘录 #include <iostream> #include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int maxn=100+5; int R,C; int a[maxn][maxn]; int d[maxn][maxn]; int dr[]={0,-1,0,1};

POJ 1088滑雪 记忆化搜索

#include <cstdio> #include <iostream> #include <algorithm> #include <queue> #include <stack> #include <cstdlib> #include <cmath> #include <set> #include <map> #include <vector> #include <cstri