HDU3480_区间DP平行四边形优化
做到现在能一眼看出来是区间DP的问题了
也能够知道dp[i][j]表示前 i 个节点被分为 j 个区间所取得的最优值的情况
cost[i][j]表示从i到j元素区间中的值,这里可以直接排序后简单求出——也就是我们的代价函数
这样其实就能够做出来了,但是空间复杂度是n3入门的题能过,普通点的都会考察你一下斜率DP的优化和四边形不等式的优化。目前我主要就懂了平行四边形的优化
首先你要确保dp和cost这两个都满足四边形不等式这个前面有过证明的博客这里就简单一提。
(博客园真的好棒,自动保存的,刚刚不小心全关了...)
( a < b <= c< d )
f[a][c]+f[b][d]<=f[b][c]+f[a][d]
这类不等式的满足就可以证明出决策函数s[i][j]满足上一等式——————决策函数s[i][j]表示dp[i][j]取得最优值时的k值,也就是把前 i 个分成 j 个区间 化为前 k 个分为 j - 1个区间留下一个区间 k +1 --- i这类问题,最优值k取s[i][j]
所以这个不等式就可以利用DP的层层递推性,来缩小k的遍历范围如下
i< i+1<=j< j+1
那么我 s[i][j-1]<=s[i][j]<=s[i+1][j]
所以对于我们的遍历j应该是正序的i应该是逆序的这样才能层层推嘛,对于决策函数的初始化
s[i][i] = i前i个分成i段的最优值怎么分都可以但是为了缩小范围所以取 i 更合适
s[i][1] 吧前i个元素,分成1个区间那么k的取值就是0呢
s[n+1][j] n + 1是 i越界的情况,可以看上面的决策函数的不等式,i+1是完全有越界的情况出现的,所以对于越界的情况我们统一赋值n也就是k的最大取值了
做了这种处理之后,剩下的就ojbk了,加油
这些东西昨天怎么想都想不出来,睡了一家,今天路上一想就通了,好不奇怪,所以不要太心急,追求效率是应该的但也要追求记忆时间额的效率呢,加油ACMer!
- #include <iostream>
- #include <cstdio>
- #include <string.h>
- #include <algorithm>
- #define inf (1 << 30)
- using namespace std;
- const int maxn = 1e4 + 10;
- const int maxm = 5e3 + 10;
- int dp[maxn][maxm];
- //dp[i][j]把前i个数分为j个集合所得到的最优值
- int s[maxn][maxm];
- //dp[i][j]的前面的状态
- int a[maxn];
- void init()
- {
- memset(dp,0,sizeof(dp));
- memset(s,0,sizeof(s));
- }
- int getval(int l,int r)
- {
- return (a[r] - a[l]) * (a[r] - a[l]);
- }
- int main()
- {
- int t,n,m;
- scanf("%d",&t);
- int cas = 0;
- while(t--)
- {
- scanf("%d%d",&n,&m);
- init();
- for(int i = 1;i <= n;i++)
- {
- scanf("%d",&a[i]);
- }
- sort(a+1,a+1+n);
- //用s[i][j]表示dp[i][j]取得最优解的时候k的位置的话
- //用s[i][j]来表示选dp[i][j]的最佳选择然后s[i-1][j]<=s[i][j]<=s[i][j+1]
- for(int i = 1;i <= n;i++)
- {
- dp[i][1] = getval(1,i);
- dp[i][i] = 0;
- s[i][i] = i;
- s[i][1] = 0;
- }
- for(int j = 2;j <= m;j++)
- {
- s[n+1][j] = n ;//越界情况
- for(int i = n;i >= j;i--)
- {
- dp[i][j] = inf;
- for(int k = s[i][j-1];k <= s[i+1][j];k++)
- {
- if(dp[i][j] > dp[k][j-1] + getval(k+1,i))
- {
- dp[i][j] = dp[k][j-1] + getval(k+1,i);
- s[i][j] = k;
- }
- }
- }
- }
- printf("Case %d: %d\n",++cas,dp[n][m]);
- }
- return 0;
- }
嗯嗯自己写的吧,算法有很大的优化空间,时间消耗过大,险过
而且空间占用很大,就模拟大佬的代码学习了一下滚动数组,优化空间
空间消耗过大,滚动数组
滚动数组一般在DP题和状态压缩算法方面用的多,而且优化后效率很高,推荐使用。
对什么可以滚动呢??
一共就两个东西,一个是分为区间数,一个是元素的个数、
咋一眼也就知道分的区间数应该是能滚动的,元素个数没什么好的想法
说明白一点,先看看原来没有滚动的版本
dp[i][j] > dp[k][j-1] + getval(k+1,i)
i是元素个数的限制
j是分的区间个数的限制
你看到k是要遍历的,也就是元素个数是不能压缩的,滚动数组要具备的条件就是,他一次
只用部分值,很少一部分,然后我们可以滚动存储
所以看看j,划分的区间个数,在进行更新时好像只和j-1有关呢
哈哈,空间为2的滚动数组出来了
- #include <cstdio>
- #include <string.h>
- #include <algorithm>
- #include <iostream>
- #define inf (1<<30)
- using namespace std;
- const int maxn = 1e4 +10;
- const int maxm = 1e3 + 10;
- int dp[2][maxn];//这里问题不一样了第一维是分的区间个数,第二维是元素个数
- int s[2][maxn];
- int a[maxn];
- int n,m;
- void init()
- {
- for(int i = 1;i <= n;i++)
- scanf("%d",&a[i]);
- sort(a+1,a+1+n);
- for(int i = 1;i <= n;i++)
- {
- dp[1%2][i] = (a[i] - a[1]) * (a[i] - a[1]);
- s[1%2][i] = 0;
- }
- }
- void solve()
- {
- for(int i = 2;i <= m;i++)
- {
- s[i%2][n+1] = n;
- for(int j = n;j > i;j--)
- {
- dp[i % 2][j] = inf;
- for(int k = s[(i-1)%2][j];k <= s[i%2][j+1];k++)
- {
- if(dp[(i-1) % 2][k] + (a[j] - a[k+1]) * (a[j] - a[k+1]) < dp[i%2][j])
- {
- dp[i%2][j] = dp[(i-1) % 2][k] + (a[j] - a[k+1]) * (a[j] - a[k+1]);
- s[i % 2][j] = k;
- }
- }
- }
- }
- }
- int main()
- {
- int t;
- scanf("%d",&t);
- for(int ca = 1; ca <= t;ca++)
- {
- scanf("%d%d",&n,&m);
- init();
- solve();
- printf("Case %d: %d\n",ca,dp[m%2][n]);
- }
- return 0;
- }
然后大佬的算法时间消耗也少,真的是很不错,而且dp的维度征好和我的相反
HDU3480_区间DP平行四边形优化的更多相关文章
- 蓝桥杯:合并石子(区间DP+平行四边形优化)
http://lx.lanqiao.cn/problem.page?gpid=T414 题意:…… 思路:很普通的区间DP,但是因为n<=1000,所以O(n^3)只能拿90分.上网查了下了解了 ...
- 51 nod 石子归并 + v2 + v3(区间dp,区间dp+平行四边形优化,GarsiaWachs算法)
题意:就是求石子归并. 题解:当范围在100左右是可以之间简单的区间dp,如果范围在1000左右就要考虑用平行四边形优化. 就是多加一个p[i][j]表示在i到j内的取最优解的位置k,注意能使用平行四 ...
- POJ 1160 经典区间dp/四边形优化
链接http://poj.org/problem?id=1160 很好的一个题,涉及到了以前老师说过的一个题目,可惜没往那上面想. 题意,给出N个城镇的地址,他们在一条直线上,现在要选择P个城镇建立邮 ...
- codeforces 1101F Trucks and Cities 区间dp+单调优化 好题
题目传送门 题意简述:(来自洛谷) 有n个城市坐落在一条数轴上,第ii个城市位于位置ai. 城市之间有m辆卡车穿行.每辆卡车有四个参数:si为起点编号,fi为终点编号,ci表示每行驶1个单位长 ...
- UVA - 1632 Alibaba (区间dp+常数优化)
题目链接 设$dp[l][r][p]$为走完区间$[l,r]$,在端点$p$时所需的最短时间($p=0$代表在左端点,$p=1$代表在右端点) 根据题意显然有状态转移方程$\left\{\begin{ ...
- 区间dp及优化
看了下感觉区间dp就是一种套路,直接上的板子代码就好了. 基础题ac代码:石子归并 #include<bits/stdc++.h> using namespace std; typedef ...
- 51Nod 1022 石子归并 V2(区间DP+四边形优化)
题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1022 题目大意: N堆石子摆成一个环.现要将石子有次序地合并成 ...
- hdu3480 Division(dp平行四边形优化)
题意:将n个数分成m段,每段的代价为最大值减最小值的平方,为代价最小是多少n<=10000 ,m<=5000 题解:先拍好序,从小到大,这样绝对是花费最小的,不过怎么样来做呢?一定很容易想 ...
- HDU 3506 (环形石子合并)区间dp+四边形优化
Monkey Party Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 131072/65536 K (Java/Others)Tot ...
随机推荐
- C++中 左值和右值的区别
总结: C++11中所有的值属于左值,右值两者之一. 左值引用:指的是可以放在赋值表达式左边的事物——在堆上或者栈上分配的命名对象或者其他对象成员——有明确的内存地址. 对左值的const引用创建临时 ...
- c++ 备忘
一.类型转换#include <sstream>stringstream ss;ss<<reverse(s1)<<'\t'<<reverse(s2);s ...
- BZOJ1801或洛谷2051 [AHOI2009]中国象棋
BZOJ原题链接 洛谷原题链接 这题挺难想状态的,刚看题感觉是状压,但数据\(100\)显然不可能. 注意到每行每列只能放\(0\sim 2\)个棋子,所以我们可以将这个写入状态. 设\(f[i][j ...
- redis在游戏服务器中的使用初探(三) 信息存储
摘要: 搭建了服务器环境 有了客户端 我们来假想下以下应用场景:我们简单举个实例来描述下Hash的应用场景,比如我们要存储一个用户信息对象数据,包含以下信息:用户ID,为查找的key,存储的value ...
- vue入门:axios的应用及拦截封装
一.概述 在vue2.0项目中,我们主要使用axios进行http请求. axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中. 特征: 1.从浏览器中创建X ...
- 【Linux】ODBC安装
ODBC介绍 ODBC是Open Database Connect 即开发数据库互连的简称,它是一个用于访问数据库的统一界面标准.ODBC引入一个公共接口以解决不同数据库潜在的不一致性,从而很好的保证 ...
- Python之tornado
一.快速了解Tornado框架 1)tornado简介 Tornado 和现在的主流 Web 服务器框架(包括大多数 Python 的框架)有着明显的区别:它是非阻塞式服务器,而且速度相当快.得利于其 ...
- Java语法基础课 原码 反码 补码
原码就是符号位加上真值的绝对值, 即用第一位表示符号, 其余位表示值. 反码的表示方法是:正数的反码是其本身:负数的反码是在其原码的基础上, 符号位不变,其余各个位取反. 补码的表示方法是在反码的基础 ...
- ATM自动取款机程序感想
上周四的Java考试,老师并没有我们考暑假给我们布置的样卷的java程序,而是让我们做一个设计ATM的程序,然而这个对于我们来说好难,因为暑假没有学好java,首先基础知识还没有掌握,输入数据一开始都 ...
- 对SVC和SVR的理解
首先: support vector classify(SVC)支持分类机做二分类的,找出分类面,解决分类问题 support vector regression(SCR)支持回归机做曲线拟合.函数回 ...