hdu4745区间dp处理环形
题目地址
注意这题并不是跳连续的区间,可以跨越,只是不能跨越已经走过的点。
根据题意,举个例子:2 1 1 2 4 5 9 8 9的答案应该是 7,为什么是7呢,我们发现在开头有一个回文串,2112,结尾有一个回文串989,这样我们只要从两个回文串的中间开始跳,就能跳过7个格子。其实也就是让我们找左侧和右侧的最长回文子序列(注意不是子串,子串是连续的),然后再枚举[0,n - 1]的区间求出最大值。
这就是很简单一个区间dp了,dp[i][j]表示区间[i,j]里的最大回文子序列,状态转移方程就可以写成:
最后只要求ans = max(ans, dp[0][i] + dp[i + 1][n - 1]
就是答案了。
附上ac代码:
#include <iostream>using namespace std;
const int maxn = 1005;
int arr[maxn];
int dp[maxn][maxn];int Solve(int n) {if (n == 1) return 1;for (int i = 0; i < n; i++) dp[i][i] = 1;for (int i = 0; i < n; i++) for (int j = 0; j < i; j++) dp[i][j] = 0;for (int len = 2; len <= n; len++) {for (int i = 0; i + len - 1 < n; i++) {int j = i + len - 1;if (arr[i] == arr[j]) dp[i][j] = dp[i + 1][j - 1] + 2;else dp[i][j] = max(dp[i + 1][j], dp[i][j - 1]);}}int ans = 0;for (int i = 0; i < n; i++) ans = max(ans, dp[0][i] + dp[i + 1][n - 1]);return ans;
}
int main()
{int n = 0;while(~scanf("%d", &n)) {if (!n) break;for (int i = 0; i < n; i++) scanf("%d", &arr[i]), arr[i + n] = arr[i];printf("%d\n", Solve(n));}return 0;
}
还有一种做法就是把1-n扩展成1-2*n来解决环形的问题,然后求长度为n的区间里的最长回文子序列,就不需要向上面一样还要加起来了,但是这里需要注意,上面的情况是只要找到两个回文子序列以后就不需要管起点在哪里,因为在两个序列的任意一个中点开始就可以了,但是这种办法不行,举个例子:1 1 2 1,我们拓展成:1 1 2 1 1 1 2 1,可以看见长度为n的最长子序列只有3,可是答案是4,因为我们是从一个不是最长回文子序列的地方开始的,答案可能可以加1,所以还要和dp[i + n - 2] + 1
作比较。
贴上ac代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1005;
int a[maxn<<1];
int dp[maxn<<1][maxn<<1];
int main(){int n;while(scanf("%d",&n) == 1 && n){for(int i = 1; i <= n; i++){scanf("%d", &a[i]);a[i + n] = a[i];dp[i][i] = dp[i + n][i + n] = 1;}for(int len = 2; len <= (n<<1); len++) //长度for(int i = 1; i <= 2 * n - len + 1; i++){ //起始位置int j = i + len - 1; //终点位置dp[i][j] = max(dp[i][j - 1], dp[i + 1][j]);if(a[i] == a[j])dp[i][j] = dp[i + 1][j - 1] + 2;}int ans = 0;for(int i = 1; i <= n; i++)ans = max(ans, dp[i][i + n - 1]);for(int i = 1; i <= n; i++)ans = max(ans, dp[i][i + n - 2] + 1);printf("%d\n",ans);}return 0;
}
hdu4745区间dp处理环形相关推荐
- 区间DP之环形石子合并
环形石子合并 题目传送门 题目描述 将 n 堆石子绕圆形操场排放,现要将石子有序地合并成一堆. 规定每次只能选相邻的两堆合并成新的一堆,并将新的一堆的石子数记做该次合并的得分. 请编写一个程序,读入堆 ...
- AcWing 320. 能量项链(环形区间DP)
AcWing 320. 能量项链(环形区间DP) 一. 问题: 二.分析: 三.代码 一. 问题: 二.分析: 在讲解这道题之前,大家需要对线性区间DP和环形区间DP有一定的了解,因此如果不会这两个知 ...
- AcWing 1068. 环形石子合并(环形区间DP)
AcWing 1068. 环形石子合并(环形区间DP) 一.问题 二.思路 三.代码 一.问题 二.思路 在讲解这道题之前,我们需要先掌握线性的区间DP问题,如果对于线性区间DP的解决方式还不了解的话 ...
- 上元节的灯会(灭)-区间dp
题目背景 上元节的庙会上,牛宝靠自己的聪明才智成功破解了花灯阵,点亮了在场所有花灯,但他没料到的是这个游戏包含AB两个项目,A项目就是点亮所有花灯,而B项目则是熄灭所有花灯.不过点亮的是花灯阵,熄灭的 ...
- 动态规划 —— 区间 DP
[概述] 区间型动态规划,又称为合并类动态规划,是线性动态规划的扩展,它在分阶段地划分问题时,与阶段中元素出现的顺序和由前一阶段的区间中哪些元素合并而来有很大的关系. [思想] 区间 DP 实质上就是 ...
- 区间DP例题(持续更新)
区间DP例题(持续更新) 做了这几道题之后发现基本的区间dp其实也就是那回事: 找出状态方程(基本上都长的差不多),然后用递推思维由小区间求得大区间: 可能某些问题会有些其他处理,只需要稍微改下就行了 ...
- Circular Barn Revisited (区间DP)
Circular Barn Revisited (区间DP) 题意:nnn头牛进nnn个对应房子(环形),每头牛所走路径贡献(length−1)×cnt(length-1) \times cnt(le ...
- 区间DP小结(附经典例题)
写这篇文章的目的主要是想总结下区间DP的经典题目,同时给自己复习巩固这方面知识点. 区间DP 一.定义 区间DP是线性动态规划的扩展,适用场景为每段区间的最优解可以通过更小区间的最优解得到.所以我 ...
- 区间DP(基础+提高)
区间DP 1.区间dp的定义 2.石子合并 2.1 思路 2.2 时间复杂度分析 2.3 AC代码 3.环形石子合并 3.1思路 3.2 时间复杂度优化 3.3 AC代码 4.能量项链 4.1思路 4 ...
最新文章
- 史上最大“云办公”实验开始,你参加了吗?
- 邮件 自动打印 linux,Unix / Linux基本实用程序-打印,电子邮件
- cursor的moveToNext()与moveToFirst()
- linux内核链表使用例,Linux设备驱动工程师之路——内核链表的使用
- php7连接mongodb,批量添加数据
- 虚拟机VirtualBox中Ubuntu无法全屏(终极解决方法)
- gcc对C语言的扩展:局部标签声明(Locally Declared Labels)
- 在配置静态IP的时候遇到 :bringing up interface eth0 : error unknown connection
- RDLC报表---自定义数据集
- 打印机如何共享多台电脑_多台电脑打印机共享的方法
- C++中list的各种使用
- Java常见的8种数据结构
- Axure RP9快捷键
- SpringBoot 集成 TkMybatis
- java编写记事本代码
- CDR是什么?CorelDRAW矢量绘图
- photoshop cs6用户界面字体太小的解决方案
- 一个屌丝程序员的青春(五一)
- Vue中 directive 用法
- Java注解详解和自定义注解实战,用代码讲解