hdu5693D++游戏 区间DP-暴力递归
主要的收获是。。如何优化你递推式里面不必要的决策
之前的代码
这个代码在HDU超时了,这就对了。。这个复杂度爆炸。。
但是这个思路非常地耿直。。那就是只需要暴力枚举删两个和删三个的情况,于是就非常耿直的枚举是哪两个n^2,是哪三个n^3
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring> using namespace std;
int T,n,m;
int a[305],d[305];
bool f[305][305];
//定向从左往右删除
int dp[305][305];
int dfs(int l,int r){
// printf("l%d r%d\n",l,r);
if(dp[l][r]!=-1) return dp[l][r];
if(l>=r) return dp[l][r]=0;
int i,j,k,p=0;
//枚举删两个
for(i=l;i<r;++i)
for(j=i+1;j<=r;++j)
{
//删i,j
//如果dfs(x,y)==y-x+1,则说明[x,y]能被完全删除
// printf("part:: i%d j%d\n",i,j);
if(f[i][j]&&(dfs(i+1,j-1)==j-i-1)){
// printf("Tpart:: i%d j%d\n",i,j);
p=max(p,(j-i+1)+dfs(l,i-1)+dfs(j+1,r));
// printf("VAL:: %d\n",p);
}
}
//枚举删三个
for(i=l;i<r;++i)
for(j=i+1;j<r;++j)
for(k=j+1;k<=r;++k)
{
// printf("part:: i%d j%d k%d\n",i,j,k);
if(f[i][j]&&f[j][k]&&(a[j]-a[i]==a[k]-a[j])&&(dfs(i+1,j-1)==j-i-1)&&(dfs(j+1,k-1)==k-j-1)){
// printf("Tpart:: i%d j%d k%d\n",i,j,k);
p=max(p,(k-i+1)+dfs(l,i-1)+dfs(k+1,r));
// printf("VAL:: %d\n",p);
}
}
return dp[l][r]=p;
}
void solve(){
memset(dp,0,sizeof(dp));
int l,r,i,j,k,len;
for(len=2;len<=n;++len){
for(l=1;l<n;++l){
r=l+len-1;
printf("DP l%d r%d\n",l,r);
if(l>=r) continue;
for(i=l;i<r;++i){
for(j=i+1;j<=r;++j){
printf("part2 ASK (%d,%d) (%d,%d)\n",l,i-1,j+1,r);
if(f[i][j]&&dp[i+1][j-1]==j-i-1) {
// printf("part2 ask (%d,%d) (%d,%d)\n",l,i-1,j+1,r);
dp[l][r]=max(dp[l][r],(j-i+1)+dp[l][i-1]+dp[j+1][r]);
}
}
}
for(i=l;i<r;++i){
for(j=i+1;j<r;++j){
for(k=j+1;k<=r;++k){
printf("part3 ASK (%d,%d) (%d,%d)\n",l,i-1,k+1,r);
if(f[i][j]&&f[j][k]&&(a[j]-a[i]==a[k]-a[j])&&dp[i+1][j-1]==j-i-1&&dp[j+1][k-1]==k-j-1){
// printf("part3 ask (%d,%d) (%d,%d)\n",l,i-1,k+1,r);
dp[l][r]=max(dp[l][r],(k-i+1)+dp[l][i-1]+dp[k+1][r]);
}
}
}
}
}
}
}
int main(){
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
int i,j,k;
for(i=1;i<=n;++i) scanf("%d",a+i);
for(i=1;i<=m;++i) scanf("%d",d+i);
memset(f,0,sizeof(f));
for(i=1;i<n;++i)
for(j=i+1;j<=n;++j)
for(k=1;k<=m;++k) f[i][j]|=(a[j]-a[i]==d[k]);
solve();
printf("%d\n",dp[1][n]);
}
return 0;
}
我们发现了一个枚举的方法是
在区间[l,r],要么我们只取l,r这两个数删掉
要么枚举在区间[l,r]内的分割点k,于是我们只需要考虑l,k,r这三个数能不能删掉
注意到我们l,r是必选的。。这样就不能形成最后一次删掉的数字在中间
于是我们枚举l,r不是必选的情况,递归分成两个子区间,将这个不选的决策交给子区间,这样我们就发现有了这个分解的步骤
即使采用了上述前两个策略。。凭借只用短长度区间l,r全选和,l,k,r全选就能形成所有的决策,我认为这个想法是非常巧妙的
虽然大佬们认为可能这很显然Orz,但是不得不说这种递归策略非常巧妙。。可能是我还没掌握精髓吧。。
放上1499ms/3000ms的代码
细节:小心r越界,因为我的len一直枚举到n,
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring> using namespace std;
int T,n,m;
int a[305],d[305];
bool f[305][305];
//定向从左往右删除
int dp[305][305];
void solve(){
memset(dp,0,sizeof(dp));
int l,r,i,j,k,len;
for(len=2;len<=n;++len){
for(l=1;l<n;++l){
r=l+len-1;
// printf("DP (%d,%d)\n",l,r);
if(r>n) continue;
if(l>=r) continue;
// printf("ASK (%d,%d) \n",l+1,r-1);
if(f[l][r]&&dp[l+1][r-1]==r-l-1)
dp[l][r]=max(dp[l][r],2+dp[l+1][r-1]);
for(i=l;i<r;++i) {
// printf("ASK (%d,%d) (%d,%d)\n",l,i,i+1,r);
dp[l][r]=max(dp[l][r],dp[l][i]+dp[i+1][r]);//当前区间保留头尾的情况
//这一句是我所需要的精华。。
}
for(k=l;k<=r;++k){
// printf("ASK (%d,%d) (%d,%d)\n",l+1,k-1,k+1,r-1);
if(f[l][k]&&f[k][r]&&(a[k]-a[l]==a[r]-a[k])&&dp[l+1][k-1]==k-l-1&&dp[k+1][r-1]==r-k-1){
dp[l][r]=max(dp[l][r],r-l+1);
}
}
}
}
}
int main(){
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
int i,j,k;
for(i=1;i<=n;++i) scanf("%d",a+i);
for(i=1;i<=m;++i) scanf("%d",d+i);
memset(f,0,sizeof(f));
for(i=1;i<n;++i)
for(j=i+1;j<=n;++j)
for(k=1;k<=m;++k) f[i][j]|=(a[j]-a[i]==d[k]);
solve();
printf("%d\n",dp[1][n]);
}
return 0;
}
hdu5693D++游戏 区间DP-暴力递归的更多相关文章
- 圆桌游戏(区间DP)
2.圆桌游戏 (game.cpp/c/pas) [问题描述] 有一种圆桌游戏是这样进行的:n个人围着圆桌坐成一圈,按顺时针顺序依次标号为1号至n号.对1<=i<=n的i来说,i号的左边是i ...
- P1005 矩阵取数游戏[区间dp]
题目描述 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的\(m*n\)的矩阵,矩阵中的每个元素\(a_{i,j}\)均为非负整数.游戏规则如下: 每次取数时须从每行各取走一个元素,共n个.经过m次后 ...
- BZOJ 2121: 字符串游戏 区间DP + 思维
Description BX正在进行一个字符串游戏,他手上有一个字符串L,以及其他一些字符串的集合S,然后他可以进行以下操作:对 于一个在集合S中的字符串p,如果p在L中出现,BX就可以选择是否将其删 ...
- 洛谷 P1043 数字游戏 区间DP
题目描述 丁丁最近沉迷于一个数字游戏之中.这个游戏看似简单,但丁丁在研究了许多天之后却发觉原来在简单的规则下想要赢得这个游戏并不那么容易.游戏是这样的,在你面前有一圈整数(一共n个),你要按顺序将其分 ...
- 多边形游戏——区间dp
题目描述 多边形(Polygon)游戏是单人玩的游戏,开始的时候给定一个由N个顶点构成的多边形(图1所示的例子中,N=4),每个顶点被赋予一个整数值,而每条边则被赋予一个符号:+(加法运算)或者*(乘 ...
- qscoj 喵哈哈村的打印机游戏 区间dp
点这里去看题 区间dp ,dp[l][r][d]代表从l到r的区间底色为d,具体看代码 第一次见到区间dp...两个小时对着敲了五遍终于自己敲懂了一遍ac #include<bits/stdc+ ...
- 【bzoj2121】字符串游戏 区间dp
题目描述 给你一个字符串L和一个字符串集合S,如果S的某个子串在S集合中,那么可以将其删去,剩余的部分拼到一起成为新的L串.问:最后剩下的串长度的最小值. 输入 输入的第一行包含一个字符串,表示L. ...
- Leetcode_877. 石子游戏(区间dp)
偶数堆石子,只能从首尾取,取多的赢. 每次操作会产生两个子状态,区间dp,记得先枚举长度. code class Solution { public: int dp[505][505]; bool s ...
- 1166 矩阵取数游戏[区间dp+高精度]
1166 矩阵取数游戏 2007年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题解 题目描述 Description [ ...
随机推荐
- Docker下梦织CMS的部署
摘要:Docker的广泛应用相对于传统的虚拟机而言提高了资源的利用率,推广后docker的影响不容忽视,在启动速度.硬盘.内存.运行密度.性能.隔离性和迁移性方面都有很大的提高.本次实训我们在cent ...
- 渗透测试中期--漏洞复现--MS08_067
靶机:Win2k3 10.10.10.130 攻击机:BT5 10.10.10.128 一:nmap 查看WinK3是否开放端口3389 开放3389方法:我的电脑->属性-&g ...
- 前端知识(一)04 Vue.js入门-谷粒学院
目录 一.介绍 1.Vue.js 是什么 2.初识Vue.js 二.基本语法 1.基本数据渲染和指令 2.双向数据绑定 3.事件 4.修饰符 5.条件渲染 6.列表渲染 7.实例生命周期 一.介绍 1 ...
- uni-app开发经验分享二: uni-app生命周期记录
应用生命周期(仅可在App.vue中监听) 页面生命周期(在页面中添加) 当页面中需要用到下拉刷新功能时,打开pages.json,在"globalStyle"里设置"e ...
- CMU数据库(15-445)-实验2-B+树索引实现(中)删除
3. Delete 实现 附上实验2的第一部分 https://www.cnblogs.com/JayL-zxl/p/14324297.html 3. 1 删除算法原理 如果叶子结点中没有相应的key ...
- vue-cli快速创建项目,可视化创建
之前学习了交互式创建,发现过程无聊,而且不方便,后面又学习了图形可视化创建,下面进行分享 1.打开cmd 2.输入vue ui,输入后会出现如下 C:\Users\12235>vue ui St ...
- 如何在Redis中实现事务
如何在Redis中实现事务 - 微店技术团队 - SegmentFault 思否 https://segmentfault.com/a/1190000007429197
- Atlas 2.1.0 实践(4)—— 权限控制
Atlas的权限控制非常的丰富,本文将进行其支持的各种权限控制的介绍. 在atlas-application.properties配置文件中,可以设置不同权限的开关. atlas.authentica ...
- 利用powershell隐藏执行后门
运行后门时,有些后门不能中断.双击运行这种后门会产生一个黑框. 一条命令就能使其在后台执行 命令解释: start-process启动一个进程 -windowstyle窗口样式 hidden隐藏
- BGP( Border Gateway Protocol)---边界网关协议
摘自: https://blog.csdn.net/weixin_43751619/article/details/84954755 一,BGP协议原理与配置 边界网关协议( Border Gatew ...