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

  1. #include <iostream>
  2. using namespace std;
  3. //***********************常量定义*****************************
  4. const int V_MAX = 305;
  5. const int P_MAX = 35;
  6. const int INF = 999999999;
  7. //*********************自定义数据结构*************************
  8. //********************题目描述中的变量************************
  9. //村庄数
  10. int vNum;
  11. //邮局数
  12. int pNum;
  13. //村庄坐标
  14. int vPos[V_MAX];
  15. //**********************算法中的变量**************************
  16. //d[i][j]表示在村庄i和村庄j之间建1个Post office的最小距离和
  17. int d[V_MAX][V_MAX];
  18. //dp[i][j]表示在村庄1和村庄i之间建j个Post office的最小距离和
  19. int dp[V_MAX][P_MAX];
  20. //***********************算法实现*****************************
  21. void Solve()
  22. {
  23. int i, j, k;
  24. //利用DP,计算d[i][j]的值
  25. for( i=1; i<=vNum; i++ )
  26. {
  27. for( j=i+1; j<=vNum; j++ )
  28. {
  29. d[i][j] = d[i][j-1] + ( vPos[j] - vPos[( i + j )/2] );
  30. }
  31. }
  32. for( i=1; i<=vNum; i++ )
  33. {
  34. dp[i][0] = INF;
  35. }
  36. //利用DP,计算dp[i][j]的值
  37. for( i=1; i<=vNum; i++ )
  38. {
  39. for( j=1; j<=pNum && j<=i; j++ )
  40. {
  41. int min = INF;
  42. for( k=j-1; k<i; k++ )
  43. {
  44. if( dp[k][j-1] + d[k+1][i] < min )
  45. min = dp[k][j-1] + d[k+1][i];
  46. }
  47. dp[i][j] = min;
  48. }
  49. }
  50. cout << dp[vNum][pNum] << endl;
  51. }
  52. //************************main函数****************************
  53. int main()
  54. {
  55. //freopen( "in.txt", "r", stdin );
  56. cin >> vNum >> pNum;
  57. for( int i=1; i<=vNum; i++ )
  58. {
  59. cin >> vPos[i];
  60. }
  61. Solve();
  62. return 0;
  63. }

POJ1037

  1. #include <iostream>
  2. using namespace std;
  3. //***********************常量定义*****************************
  4. const int MAX_N = 25;
  5. //*********************自定义数据结构*************************
  6. //********************题目描述中的变量************************
  7. //木条的数目
  8. int n;
  9. //栅栏的编号
  10. long long c;
  11. //**********************算法中的变量**************************
  12. //up[n][i]表示:n个木条,且第一个木条长度为i的上升型栅栏数目
  13. long long up[MAX_N][MAX_N];
  14. //down[n][i]表示:n个木条,且第一个木条长度为i的下降型栅栏数目
  15. long long down[MAX_N][MAX_N];
  16. bool used[MAX_N];
  17. bool isPrint;
  18. //***********************算法实现*****************************
  19. void FillTable()
  20. {
  21. down[1][1] = 1;
  22. up[1][1] = 1;
  23. down[2][1] = 0;
  24. up[2][1] = 1;
  25. down[2][2] = 1;
  26. up[2][2] = 0;
  27. int i, j, k;
  28. for( i=3; i<MAX_N; i++ )
  29. {
  30. //??? j<=MAX_N
  31. for( j=1; j<MAX_N; j++ )
  32. {
  33. //??? k=j
  34. for( k=j; k<i; k++ )
  35. {
  36. up[i][j] += down[i-1][k];
  37. }
  38. for( k=1; k<j; k++ )
  39. {
  40. down[i][j] += up[i-1][k];
  41. }
  42. }
  43. }
  44. }
  45. void SolveAndPrint( int id, int count )
  46. {
  47. for( int i=1; i<=count; i++ )
  48. {
  49. if( used[i] && i<=id )
  50. {
  51. id++;
  52. count++;
  53. }
  54. }
  55. used[id] = true;
  56. if( isPrint )
  57. {
  58. cout << " " << id;
  59. }
  60. else
  61. {
  62. cout << id;
  63. isPrint = true;
  64. }
  65. }
  66. //************************main函数****************************
  67. int main()
  68. {
  69. //freopen( "in.txt", "r", stdin );
  70. int caseNum;
  71. cin >> caseNum;
  72. //DP的填表
  73. FillTable();
  74. while( caseNum-- )
  75. {
  76. cin >> n >> c;
  77. //先搜索down
  78. bool isDown = true;
  79. bool isFirst = true;
  80. int id = 1;
  81. isPrint = false;
  82. memset( used, 0, sizeof(used) );
  83. while( n )
  84. {
  85. if( isDown )
  86. {
  87. if( c > down[n][id] )
  88. {
  89. c -= down[n][id++];
  90. if( isFirst )
  91. {
  92. //设置标记,下次搜索up
  93. isDown = false;
  94. //对每个id有down和up两个值
  95. //确定第一个数时,down和up都要搜索
  96. id--;
  97. }
  98. }
  99. else
  100. {
  101. //如果当前木条长度可确定
  102. //问题规模减一
  103. SolveAndPrint( id, n-- );
  104. isFirst = false;
  105. isDown = false;
  106. id = 1;
  107. }
  108. }
  109. else
  110. {
  111. if( c > up[n][id] )
  112. {
  113. c -= up[n][id++];
  114. if( isFirst )   isDown = true;
  115. }
  116. else
  117. {
  118. SolveAndPrint( id, n-- );
  119. isFirst = false;
  120. isDown = true;
  121. }
  122. }
  123. }
  124. cout << endl;
  125. }
  126. return 0;
  127. }

版权声明:本文为博主原创文章,未经博主允许不得转载。

DP---基本思想 具体实现 经典题目 POJ1160 POJ1037的更多相关文章

  1. TOJ4101.Guess Game(TOJ means Tianjin University Online Judge)(dp的思想,但这道题目是假dp)

    题意:你要从[1,n]这个n个数中猜出来规定的某个数,现在这个数未知,问你在最糟糕的情况下(但是你采用了最优的策略),你要猜多少次才能猜出这个数.现在有两种条件: 第一种:当你猜的数比指定的那个数小的 ...

  2. LOJ 2743(洛谷 4365) 「九省联考 2018」秘密袭击——整体DP+插值思想

    题目:https://loj.ac/problem/2473 https://www.luogu.org/problemnew/show/P4365 参考:https://blog.csdn.net/ ...

  3. 学习心得:《十个利用矩阵乘法解决的经典题目》from Matrix67

    本文来自:http://www.matrix67.com/blog/archives/tag/poj大牛的博文学习学习 节选如下部分:矩阵乘法的两个重要性质:一,矩阵乘法不满足交换律:二,矩阵乘法满足 ...

  4. 【转】Matrix67:十个利用矩阵乘法解决的经典题目

    好像目前还没有这方面题目的总结.这几天连续看到四个问这类题目的人,今天在这里简单写一下.这里我们不介绍其它有关矩阵的知识,只介绍矩阵乘法和相关性质.    不要以为数学中的矩阵也是黑色屏幕上不断变化的 ...

  5. [leetcode]53Maximum Subarray动态规划经典题目:最大子串问题

    /** * Find the contiguous subarray within an array (containing at least one number) * which has the ...

  6. dfs与dp算法之关系与经典入门例题

    目录 声明 dfs与dp的关系 经典例题-数字三角形 - POJ 1163 题目 dfs思路 解题思路 具体代码 dp思路 解题思路 具体代码 声明 本文不介绍dfs.dp算法的基础思路,有想了解的可 ...

  7. POJ 1947 Rebuilding Roads (树dp + 背包思想)

    题目链接:http://poj.org/problem?id=1947 一共有n个节点,要求减去最少的边,行号剩下p个节点.问你去掉的最少边数. dp[u][j]表示u为子树根,且得到j个节点最少减去 ...

  8. POJ 2411 Mondriaan's Dream (状压DP,骨牌覆盖,经典)

    题意: 用一个2*1的骨牌来覆盖一个n*m的矩形,问有多少种方案?(1<=n,m<=11) 思路: 很经典的题目,如果n和m都是奇数,那么答案为0.同uva11270这道题. 只需要m个b ...

  9. 10.22~10.28一周经典题目整理(meeting,BZOJ4377,POJ3659)

    meeting:给正n边形每个点染上黑色或者白色,问有多少个同色的等腰三角形. 以正五边形为例这里将最上面的点作为顶点,得到若干对相等的腰 ,注意到以最上面的点作为顶点的等腰三角形的个数,等于颜色相等 ...

随机推荐

  1. Uncaught SyntaxError: Unexpected token : 开发遇到的跨域问题

    先描述一下,这个问题,是如何遇到的 在ajax调用远程服务的时候,报了一个Origin xxxxxx is not allowed by Access-Control-Allow-Origin 的错误 ...

  2. 物联网通信 - RESTDemo示例程序(C#版本)

    技术:wcf+http post+json(.net4.0 + jdk1.8) 运行环境:vs2010+java 概述Server开放RESTful API接口,供应用程序/移动App/嵌入式qt通过 ...

  3. 20190305-leetcode题目有效的括号

    给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效. 有效字符串需满足: 左括号必须用相同类型的右括号闭合. 左括号必须以正确的顺序闭合. 注意空字符串可被认 ...

  4. 阿里云ubantu16.04 搭建LAMP环境

    1.登录服务器 2.sudo apt-get update 更新软件列表 3.sudo apt-get install lamp-server^  (注意右上角的' ^ '这个不能少) 输入apach ...

  5. 使用JSTL的taglib做if判断

    背景:使用springmvc做RESTful风格的CRUD时 问题:使用JSTL的taglib做if判断,未能呈现判断后想要的内容 排查过程: 1.先确定了转发到了正确的jsp文件(在jsp页面中增加 ...

  6. 08-可滚动Widget

    可滚动Widget ViewPort视口 在Flutter中,术语ViewPort(视口),如无特别说明,则是指一个Widget的实际显示区域.例如,一个ListView的显示区域高度是800像素,虽 ...

  7. 使用WinIO库实现保护模式下的IO和内存读写

    问题已解决: 原因是函数的调用方式与WinIO中不一致,使用的时候漏掉了__stdcall. 函数原定义为: 在实际的GPIO读写中遇到以下问题: SetPortVal可正常写入,但是GetPortV ...

  8. CSS深入理解absolute

    1.图片目标来覆盖,无依赖,真不赖: 2.如何定位下拉框,最佳实践来分享: 3.对其居中或边缘,定位实现有脸面: 4.星号时有时没有,破坏队形不用愁: 5.图文对其兼容差,绝对定位来开挂: 6.文字溢 ...

  9. javaweb(七)——HttpServletResponse对象(一)

    Web服务器收到客户端的http请求,会针对每一次请求,分别创建一个用于代表请求的request对象.和代表响应的response对象.request和response对象即然代表请求和响应,那我们要 ...

  10. swift实现UItableview上拉下拉刷新模块

    最近用写个项目 发现上拉下拉刷新模块没找到合适的 so 自己写了一个 由于最近忙 教程就不写了 里面有 直接贴地址https://github.com/DaChengTechnology/DCRefr ...