题目大意

将一些连续的序列根据颜色分为N段,每段有颜色 为 Ci, 长度为 Li。每次点击其中的一段 i ,则可以将该段i消除,该段相邻的两段自动连接到一起,如果连接到一起的两段之前的颜色相同,则更新该段的长度。消除过程可以得到得分 Li*Li。求当所有的段都消除完毕时的最多得分。

分析

求最优化问题,典型的动态规划。 
(1)考虑前n个段被消除最大得分,求dp[n]? 
    显然不行,因为无法保证无后效性,因为这种递推从前向后,如果先消除了前i个段,则前i个段中可能和后面的段合并后再消除的情况就不存在了,即无法表示所有的情况。这样就导致无法构成递推关系,即即使知道了dp[0], dp[1], ....dp[n-1], 也无法知道 dp[n]; 
(2)考虑 段i到段j之间被消除的最大得分,求 dp[0][n-1]? 即区间动态规划 
    既然要求完全消除 [i...j] 的得分,则必定要先消除一个,就从最后一个段j开始。此时有两种选择: 
        1、直接消除j,得分Lj*Lj. 
        2、先消除j之前的某些段,遇到一个颜色和j相同的段,将该段和j进行合并(由于j之前可能有多个间隔的和j颜色相同的段s,因此需要进行枚举取最大值) 
    但是,在第二种选择中,将j和某个段s进行合并之后,得到一个新的段,此时是直接消除该大段,还是继续选择将该大段和之前的某个段s1合并后再消除? 
    如果需要构造递推关系,则有 dp[i][j] = max(dp[i][j], dp[i][s'] + dp[s+1][j-1]) 
其中 dp[s+1][j-1]是将 s到j之间的先消除,将s和j进行合并,设s和j合并后得到的段为s',dp[i][s']是将i到 s'进行合并后的得分。 
    这样做,明显会改变原来的段的大小结构,多个段进行交叉操作时会乱,无法保证无后效性。

(3)进一步考虑: 
dp数组,dp[i][j][k] 表示从下i到j的连续的段,且j之后有长度为k的颜色和 Seq[j]相同,但是不和j相邻的段, 
将 [i, j] 内的段完全消除,且将j之后的那长度为k的段也消除,能够得到的最大分数 
注意,消除的时候,分值不包括 j到长度为k的段之间的那些数据消除的得分

这样构造状态,就可以形成递推关系: 
dp[i][j][k] = dp[i][j-1][0] + (k+Lj)*(k+Lj) 
dp[i][j][k] = max(dp[i][j][k], dp[i][s][k + Lj] + dp[s+1][j-1][0])

实现(c++)

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#define MAX_SEG_NUM 202 //保存每段的数据,颜色和长度
struct Seg{
int color;
int length;
};
Seg gSegs[MAX_SEG_NUM];
//dp数组,dp[i][j][k] 表示从下i到j的连续的段,且j之后有长度为k的颜色和 Seq[j]相同,但是不和j相邻的段,
//将 [i, j] 内的段完全消除,且将j之后的那长度为k的段也消除,能够得到的最大分数
//注意,消除的时候,分值不包括 j到长度为k的段之间的那些数据消除的得分
int dp[MAX_SEG_NUM][MAX_SEG_NUM][MAX_SEG_NUM]; int Square(int x){
return x*x;
}
//dp函数。采用递归式的动态规划
int GetScore(int start, int end, int ex_len){
//如果已经求完,则直接返回
if (dp[start][end][ex_len])
return dp[start][end][ex_len]; int result = Square(gSegs[end].length + ex_len); //将段j和j之后长度为k的段进行合并,直接消除求出结果
if (start == end) //递归结束
return dp[start][end][ex_len] = result; result += GetScore(start, end - 1, 0);
//方案一:将段j和j之后长度为k的段进行合并消除,然后加上 i 到j 之间的段进行求和(注意 ex_len 为0是因为
//在求 dp[i][j][k]的时候,分值不包括 j到长度为k的段之间的那些数据的得分,因此 求 i到j-1之间的消除得分即可,即 ex_len = 0 //方案二:在将j和j之后长度为k的段放在一块之后,先不消除,而是递归到子问题:
//从i到j之间找出s,使得s的颜色和j的颜色相同,然后先消去 s+1到j-1 之间的部分SS,则子问题 为 dp[i][s][length(j) + k] + SS
//从 SS中取出最大值
for (int i = end - 1; i >= start; i--){
if (gSegs[i].color != gSegs[end].color)
continue;
int tmp = GetScore(start, i, ex_len + gSegs[end].length) + GetScore(i + 1, end - 1, 0);
if (tmp > result)
result = tmp;
}
return dp[start][end][ex_len] = result;
}
int main(){
int cas, c = 1;
int total_num, color, last_color, k;
scanf("%d", &cas);
while (c <= cas){
scanf("%d", &total_num);
last_color = -1;
k = -1;
memset(dp, 0, sizeof(dp));
for (int i = 0; i < total_num; i++){
scanf("%d", &color);
if (last_color != color){
k++;
last_color = color;
gSegs[k].length = 0;
gSegs[k].color = color;
}
gSegs[k].length++;
} printf("Case %d: %d\n", c++, GetScore(0, k, 0));
}
return 0;
}

poj_1390 动态规划的更多相关文章

  1. 增强学习(三)----- MDP的动态规划解法

    上一篇我们已经说到了,增强学习的目的就是求解马尔可夫决策过程(MDP)的最优策略,使其在任意初始状态下,都能获得最大的Vπ值.(本文不考虑非马尔可夫环境和不完全可观测马尔可夫决策过程(POMDP)中的 ...

  2. 简单动态规划-LeetCode198

    题目:House Robber You are a professional robber planning to rob houses along a street. Each house has ...

  3. 动态规划 Dynamic Programming

    March 26, 2013 作者:Hawstein 出处:http://hawstein.com/posts/dp-novice-to-advanced.html 声明:本文采用以下协议进行授权: ...

  4. 动态规划之最长公共子序列(LCS)

    转自:http://segmentfault.com/blog/exploring/ LCS 问题描述 定义: 一个数列 S,如果分别是两个或多个已知数列的子序列,且是所有符合此条件序列中最长的,则 ...

  5. C#动态规划查找两个字符串最大子串

     //动态规划查找两个字符串最大子串         public static string lcs(string word1, string word2)         {            ...

  6. C#递归、动态规划计算斐波那契数列

    //递归         public static long recurFib(int num)         {             if (num < 2)              ...

  7. 动态规划求最长公共子序列(Longest Common Subsequence, LCS)

    1. 问题描述 子串应该比较好理解,至于什么是子序列,这里给出一个例子:有两个母串 cnblogs belong 比如序列bo, bg, lg在母串cnblogs与belong中都出现过并且出现顺序与 ...

  8. 【BZOJ1700】[Usaco2007 Jan]Problem Solving 解题 动态规划

    [BZOJ1700][Usaco2007 Jan]Problem Solving 解题 Description 过去的日子里,农夫John的牛没有任何题目. 可是现在他们有题目,有很多的题目. 精确地 ...

  9. POJ 1163 The Triangle(简单动态规划)

    http://poj.org/problem?id=1163 The Triangle Time Limit: 1000MS   Memory Limit: 10000K Total Submissi ...

随机推荐

  1. Accumulator

    Accumulator简介 Accumulator是spark提供的累加器,顾名思义,该变量只能够增加. 只有driver能获取到Accumulator的值(使用value方法),Task只能对其做增 ...

  2. 利用HttpClient写的一个简单页面获取

    之前就听说过利用网络爬虫来获取页面,感觉还挺有意思的,要是能进行一下偏好搜索岂不是可以满足一下窥探欲. 后来从一本书上看到用HttpClient来爬取页面,虽然也有源码,但是也没说用的HttpClie ...

  3. SQL Server 2008 压缩日志

    USE [master]GOALTER DATABASE DNName SET RECOVERY SIMPLE WITH NO_WAITGOALTER DATABASE DNName SET RECO ...

  4. java.lang.OutOfMemoryError: Java heap space 解决方法

    从网上抄过来的,因为经常碰到这个问题,记录一下. java.lang.OutOfMemoryError: Java heap space 解决方法 这个问题的根源是jvm虚拟机的默认Heap大小是64 ...

  5. js学习笔记31----工厂方式

    工厂方式构造对象: 1.原料---构造函数,创建一个对象 “构造函数”,就是专门用来生成“对象”的函数.它提供模板,作为对象的基本结构.一个构造函数,可以生成多个对象,这些对象都有相同的结构.   2 ...

  6. Jquery仿IGoogle实现可拖动窗口(源码)

    google可谓是ajax的特效用的淋漓尽致,google suggest, google map,igoogle 可拖动窗口等等...今天仿照iGoogle做了一个简单的小demo. 这个的demo ...

  7. 7 款灵巧实用的 CSS3/jQuery 工具

    作为 Web 前端开发者,应该对 jQuery 比较熟悉,对免费开源的 jQuery 也用的非常多.但是随着 CSS3 标准的诞生和发展,很多 jQuery 插件也都纷纷应用了 CSS3 新标准,也因 ...

  8. C++ 语言中的重载、内联、缺省参数、隐式转换等机制展现了很多优点

    C++ 语言中的重载.内联.缺省参数.隐式转换等机制展现了很多优点,但是这些 优点的背后都隐藏着一些隐患.正如人们的饮食,少食和暴食都不可取,应当恰到好处. 我们要辨证地看待 C++的新机制,应该恰如 ...

  9. linux -- ubuntu14.10安装gnome桌面环境和dock工具

    ubuntu14.10系统自带Unity桌面环境,但是还是习惯于gnome桌面环境,再加上dock用着就很顺手了.   方法/步骤 首先,按Ctrl+Alt+T,调出终端.在其中输入:sudo apt ...

  10. Codeforces Round #Pi (Div. 2) —— D One-Dimensional Battle Ships

    题目的意思是: 如今有一个长度为n,宽为1的方格,在上面能够放大小为1*a船,然后输入为n,k,a.分别为平地的大小,船的数量,船的长度. 一个叫alice的人已经在地图上摆好了船的位置. 然后bob ...