DP---基本思想 具体实现 经典题目 POJ1160 POJ1037
POJ1160, post office。动态规划的经典题目。呃,又是经典题目,DP部分的经典题目怎就这么多。木有办法,事实就这样。
求:在村庄内建邮局,要使村庄到邮局的距离和最小。
设有m个村庄,分别为 V1 V2 V3 … Vm, 要建n个邮局,分别为P1 P2 P3 … Pn。
在DP的问题中,经常有从m个物体中选n个物体的情况,本题显然也属于这种情况。一般可以这样考虑:假设已经选了1个,那么就成了在m-1个中选n-1个的问题了。
对于此题,也可以考虑先建一个邮局。建在哪里呢?不妨设,该邮局建在Vk+1..Vm之间的某个村庄里,而且规定Vk+1..Vm之间再不允许建立其他邮局了。因此,剩下的n-1个邮局必然出现在V1..Vk之间的村庄内,这样问题就转换成:在前k个村庄里选n-1个邮局的问题。
设dp( m,n )表示在V1…Vm之间建立n个邮局时的最短距离。
L( i, j )表示在Vi…Vj之间建立一个邮局的最短距离。

状态转换方程:
dp( m,n ) = Min( dp( k,n-1 ) + L( k+1,m ) ), 其中:1 <= k<m
编程实现:没啥说的,具体看代码。
POJ1037, a decorative fence。这个题绝对不是入门级的,如果能独立做出来,那已经很NB了。嘿嘿,这一大段英文,先要把题目看懂就得费些气力。
问题:有n个长度不同的木条,现在按照类似字典顺序(长度小的排在前)对这n个木条排序,求第m个图像是什么?
设这n个木条分别为S1 S2 S3…Sn,它们的对应长度分别为1 2 3...n.
对这n个木条进行排序,结果无非有下面n类: 以S1开头,以S2开头…以Sn开头。按照题目要求对这n类进行排序。
S1 。。。
S2 。。。
。。。
Sn 。。。
如果能算出每个区间有多少种排列,那么就能确定要求的第m个排列了。好抽象呀,还是举个例子吧。如果以S1开头的有10种排列,以S2开头的有10种排列…现在有n个木条,如果要确定第15个排列,那么就可以知道第15个排列必然是以S2开头的。因为已经知道了最终排列的第一个木条是S2,那么只要依次求出后面n-1个木条即可。如果能把S2开头的区间再划分成若干个区间,并且知道每个区间的大小就和上面的问题一样了。
S2 S1 。。。
S2 S3 。。。
。。。
S2 Sn 。。。
这时问题就转换为:有n-1个木条,现在要确定第5个排列(15-10=5,以S1开头的排列已占去了10个)
现在结合题目,题目要求出现波浪形,即有高度变换。这时以Si开头的排列又可以分成两类:第二个木条比Si高,我们记做Hi, 第二个木条比Si低,我们记做Li。这时区间细分成如下形式:
L1 。。。
H1 。。。
L2 。。。
H2 。。。
。。。。。。
Ln 。。。
Hn 。。。
要确定最终的排列,关键是要知道每个区间里排列的个数。
设L( x,n )表示n个木条的排列中,以长度为x的木条开始,且下一个木条比X低的排列数。H( x,n )表示n个木条的排列中,以长度为x的木条开始,且下一个比X高的的排列数
状态转换方程:
L( x, n ) = , 其中 1 <= i < x
H( y, n ) = , 其中 y <= i < n
有状态方程在手,就可以依次确定要求排列的每个木条。
参考资料:
http://jay23jack.blog.163.com/blog/static/317951942009130215813/
http://blog.163.com/leyni@126/blog/static/16223010220103150173663/
POJ1160
- #include <iostream>
- using namespace std;
- //***********************常量定义*****************************
- const int V_MAX = 305;
- const int P_MAX = 35;
- const int INF = 999999999;
- //*********************自定义数据结构*************************
- //********************题目描述中的变量************************
- //村庄数
- int vNum;
- //邮局数
- int pNum;
- //村庄坐标
- int vPos[V_MAX];
- //**********************算法中的变量**************************
- //d[i][j]表示在村庄i和村庄j之间建1个Post office的最小距离和
- int d[V_MAX][V_MAX];
- //dp[i][j]表示在村庄1和村庄i之间建j个Post office的最小距离和
- int dp[V_MAX][P_MAX];
- //***********************算法实现*****************************
- void Solve()
- {
- int i, j, k;
- //利用DP,计算d[i][j]的值
- for( i=1; i<=vNum; i++ )
- {
- for( j=i+1; j<=vNum; j++ )
- {
- d[i][j] = d[i][j-1] + ( vPos[j] - vPos[( i + j )/2] );
- }
- }
- for( i=1; i<=vNum; i++ )
- {
- dp[i][0] = INF;
- }
- //利用DP,计算dp[i][j]的值
- for( i=1; i<=vNum; i++ )
- {
- for( j=1; j<=pNum && j<=i; j++ )
- {
- int min = INF;
- for( k=j-1; k<i; k++ )
- {
- if( dp[k][j-1] + d[k+1][i] < min )
- min = dp[k][j-1] + d[k+1][i];
- }
- dp[i][j] = min;
- }
- }
- cout << dp[vNum][pNum] << endl;
- }
- //************************main函数****************************
- int main()
- {
- //freopen( "in.txt", "r", stdin );
- cin >> vNum >> pNum;
- for( int i=1; i<=vNum; i++ )
- {
- cin >> vPos[i];
- }
- Solve();
- return 0;
- }
POJ1037
- #include <iostream>
- using namespace std;
- //***********************常量定义*****************************
- const int MAX_N = 25;
- //*********************自定义数据结构*************************
- //********************题目描述中的变量************************
- //木条的数目
- int n;
- //栅栏的编号
- long long c;
- //**********************算法中的变量**************************
- //up[n][i]表示:n个木条,且第一个木条长度为i的上升型栅栏数目
- long long up[MAX_N][MAX_N];
- //down[n][i]表示:n个木条,且第一个木条长度为i的下降型栅栏数目
- long long down[MAX_N][MAX_N];
- bool used[MAX_N];
- bool isPrint;
- //***********************算法实现*****************************
- void FillTable()
- {
- down[1][1] = 1;
- up[1][1] = 1;
- down[2][1] = 0;
- up[2][1] = 1;
- down[2][2] = 1;
- up[2][2] = 0;
- int i, j, k;
- for( i=3; i<MAX_N; i++ )
- {
- //??? j<=MAX_N
- for( j=1; j<MAX_N; j++ )
- {
- //??? k=j
- for( k=j; k<i; k++ )
- {
- up[i][j] += down[i-1][k];
- }
- for( k=1; k<j; k++ )
- {
- down[i][j] += up[i-1][k];
- }
- }
- }
- }
- void SolveAndPrint( int id, int count )
- {
- for( int i=1; i<=count; i++ )
- {
- if( used[i] && i<=id )
- {
- id++;
- count++;
- }
- }
- used[id] = true;
- if( isPrint )
- {
- cout << " " << id;
- }
- else
- {
- cout << id;
- isPrint = true;
- }
- }
- //************************main函数****************************
- int main()
- {
- //freopen( "in.txt", "r", stdin );
- int caseNum;
- cin >> caseNum;
- //DP的填表
- FillTable();
- while( caseNum-- )
- {
- cin >> n >> c;
- //先搜索down
- bool isDown = true;
- bool isFirst = true;
- int id = 1;
- isPrint = false;
- memset( used, 0, sizeof(used) );
- while( n )
- {
- if( isDown )
- {
- if( c > down[n][id] )
- {
- c -= down[n][id++];
- if( isFirst )
- {
- //设置标记,下次搜索up
- isDown = false;
- //对每个id有down和up两个值
- //确定第一个数时,down和up都要搜索
- id--;
- }
- }
- else
- {
- //如果当前木条长度可确定
- //问题规模减一
- SolveAndPrint( id, n-- );
- isFirst = false;
- isDown = false;
- id = 1;
- }
- }
- else
- {
- if( c > up[n][id] )
- {
- c -= up[n][id++];
- if( isFirst ) isDown = true;
- }
- else
- {
- SolveAndPrint( id, n-- );
- isFirst = false;
- isDown = true;
- }
- }
- }
- cout << endl;
- }
- return 0;
- }
版权声明:本文为博主原创文章,未经博主允许不得转载。
DP---基本思想 具体实现 经典题目 POJ1160 POJ1037的更多相关文章
- TOJ4101.Guess Game(TOJ means Tianjin University Online Judge)(dp的思想,但这道题目是假dp)
题意:你要从[1,n]这个n个数中猜出来规定的某个数,现在这个数未知,问你在最糟糕的情况下(但是你采用了最优的策略),你要猜多少次才能猜出这个数.现在有两种条件: 第一种:当你猜的数比指定的那个数小的 ...
- LOJ 2743(洛谷 4365) 「九省联考 2018」秘密袭击——整体DP+插值思想
题目:https://loj.ac/problem/2473 https://www.luogu.org/problemnew/show/P4365 参考:https://blog.csdn.net/ ...
- 学习心得:《十个利用矩阵乘法解决的经典题目》from Matrix67
本文来自:http://www.matrix67.com/blog/archives/tag/poj大牛的博文学习学习 节选如下部分:矩阵乘法的两个重要性质:一,矩阵乘法不满足交换律:二,矩阵乘法满足 ...
- 【转】Matrix67:十个利用矩阵乘法解决的经典题目
好像目前还没有这方面题目的总结.这几天连续看到四个问这类题目的人,今天在这里简单写一下.这里我们不介绍其它有关矩阵的知识,只介绍矩阵乘法和相关性质. 不要以为数学中的矩阵也是黑色屏幕上不断变化的 ...
- [leetcode]53Maximum Subarray动态规划经典题目:最大子串问题
/** * Find the contiguous subarray within an array (containing at least one number) * which has the ...
- dfs与dp算法之关系与经典入门例题
目录 声明 dfs与dp的关系 经典例题-数字三角形 - POJ 1163 题目 dfs思路 解题思路 具体代码 dp思路 解题思路 具体代码 声明 本文不介绍dfs.dp算法的基础思路,有想了解的可 ...
- POJ 1947 Rebuilding Roads (树dp + 背包思想)
题目链接:http://poj.org/problem?id=1947 一共有n个节点,要求减去最少的边,行号剩下p个节点.问你去掉的最少边数. dp[u][j]表示u为子树根,且得到j个节点最少减去 ...
- POJ 2411 Mondriaan's Dream (状压DP,骨牌覆盖,经典)
题意: 用一个2*1的骨牌来覆盖一个n*m的矩形,问有多少种方案?(1<=n,m<=11) 思路: 很经典的题目,如果n和m都是奇数,那么答案为0.同uva11270这道题. 只需要m个b ...
- 10.22~10.28一周经典题目整理(meeting,BZOJ4377,POJ3659)
meeting:给正n边形每个点染上黑色或者白色,问有多少个同色的等腰三角形. 以正五边形为例这里将最上面的点作为顶点,得到若干对相等的腰 ,注意到以最上面的点作为顶点的等腰三角形的个数,等于颜色相等 ...
随机推荐
- python学习笔记(一)学习资料记录
相关资料网站 1. python3简明教程 适合新学者,因为可以在线操作,并且校验结果,同时还有考试系统.比较基础 2. python数据分析数据科学中文英文工具书籍下载 免费的中英文数据的PDF下载 ...
- 大数据学习--day14(String--StringBuffer--StringBuilder 源码分析、性能比较)
String--StringBuffer--StringBuilder 源码分析.性能比较 站在优秀博客的肩上看问题:https://www.cnblogs.com/dolphin0520/p/377 ...
- Linux 字符设备驱动—— ioremap() 函数解析
一. ioremap() 函数基础概念 几乎每一种外设都是通过读写设备上的相关寄存器来进行的,通常包括控制寄存器.状态寄存器和数据寄存器三大类,外设的寄存器通常被连续地编址.根据CPU体系结构的不同, ...
- 适合初学Altium Designer的教学视频
以下推荐的我都亲自看过,个人感觉确实不错,可以有助于了解流程,以及一些设计规范 首先是凡亿的PCB教学,贵是贵了点,不过也有免费的,讲解的很详细,而且还有专门的群,610359270 http://w ...
- 20155222 卢梓杰 myod
20155222 卢梓杰 myod 复习c文件处理内容 编写myod.c 用myod XXX实现Linux下od -tx -tc XXX的功能 main与其他分开,制作静态库和动态库 编写Makefi ...
- # 20155236 2016-2017-2 《Java程序设计》第二周学习总结
20155236 2016-2017-2 <Java程序设计>第二周学习总结 教材学习内容总结 对于类型.变量.运算符.流程控制等等的学习.在其中包含着基本的语法元素,还有基本的逻辑语句. ...
- windows phone 手机解锁失败问题
1.使用 VS 2015 自带的 Windows Phone Developer Registration (8.1) 工具, 解锁手机. 总是提示 日期和时间错误. 解决办法, 有2个 1.打 ...
- java Hibernate UUID代码
package mypack; import java.io.Serializable; import java.net.InetAddress; /** * 唯一主键生成办法.从Hibernate中 ...
- sqlserver 导出数据到Excel
1.导出非正式Excel EXEC master..xp_cmdshell 'bcp t.dbo.tcad out D:\MySelf\output\Temp.xls -c -q -S".& ...
- replace与replaceAll的区别
这两者有些人很容易搞混,因此我在这里详细讲述下. replace的参数是char和CharSequence,即可以支持字符的替换,也支持字符串的替换(CharSequence即字符串序列的意思,说白了 ...