动态规划入门(四)DP 基本思想与实现
来源:互联网 发布:淘宝中老年模特招聘 编辑:程序博客网 时间:2024/06/01 10:02
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
编程实现:没啥说的,具体看代码。
心得;
DP的基本思想与分治法的基本思想是类似的;分析如下
1.都是组合子问题的解来求解求解原问题
2.分治法将问题划分为互不相交的子问题,递归地求解子问题,再将它们的解组合起来,求出原问题的解。
3.动态规划应用与子问题重叠的情况,即不同的子问题具有公共的子子问题。
4.动态规划的实现方法是自底向上法,将子问题按规模排序,按由从小到大的顺序进行求解,当求解某个子问题时,它所依赖的更小的子问题已经求解完毕,结果已保存,每个子问题只需求解一次。
编程实现注意事项:
//dp数组必须进行初始化for(int i=1;i<=vNum;i++)dp[i][0]=INF;dp数组必须进行初始化,否则得不到正确结果
#include<iostream>using namespace std;//***************************常量定义***************************const int V_MAX=300;const int P_MAX=30;const int INF=999999;//**************************题目变量****************************//全局变量全部初始化为0int vNum;//村庄数int pNum;//邮局数int vPos[V_MAX];//村庄坐标//*************************算法变量*****************************int d[V_MAX][V_MAX];//d[i][j]表示第i个村庄与第j个村庄之间建一个邮局的最短距离int dp[V_MAX][P_MAX];//dp[m][n]表示前m个村庄里面建n个邮局的最短距离void solve(){ //计算d[i][j]for(int i=1;i<=vNum;i++)for(int j=i+1;j<=vNum;j++)d[i][j]=d[i][j-1]+(vPos[j]-vPos[(i+j)/2]); //dp数组必须进行初始化for(int i=1;i<=vNum;i++)dp[i][0]=INF;//计算dp[i][j]for(int i=1;i<=vNum;i++)for(int j=1;j<=i&&j<=pNum;j++){int min=INF;for(int 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];}int main(){cin>>vNum>>pNum;for(int i=1;i<=vNum;i++)cin>>vPos[i];solve();}
//dp数组必须进行初始化for(int i=1;i<=vNum;i++)dp[i][0]=INF;
改进程序使之能输出选择的邮件序列,其思想与poj1458的思想类似,因为dp[m][n]的值取决于dp[k][n-1] (n-1=<k<=m),所以
int flag[V_MAX][P_MAX];//flag[m][n]存储计算dp[m][n]时所选择的dp[k][n-1]的k
代码如下:
<pre name="code" class="cpp">#include<iostream>using namespace std;//***************************常量定义***************************const int V_MAX=300;const int P_MAX=30;const int INF=999999;//**************************题目变量****************************//全局变量全部初始化为0int vNum;//村庄数int pNum;//邮局数int vPos[V_MAX];//村庄坐标//*************************算法变量*****************************int d[V_MAX][V_MAX];//d[i][j]表示第i个村庄与第j个村庄之间建一个邮局的最短距离int dp[V_MAX][P_MAX];//dp[m][n]表示前m个村庄里面建n个邮局的最短距离int flag[V_MAX][P_MAX];//flag[m][n]存储计算dp[m][n]时所选择的dp[k][n-1]的kvoid solve(){ //计算d[i][j]for(int i=1;i<=vNum;i++)for(int j=i+1;j<=vNum;j++)d[i][j]=d[i][j-1]+(vPos[j]-vPos[(i+j)/2]); //dp数组必须进行初始化for(int i=1;i<=vNum;i++)dp[i][0]=INF;//计算dp[i][j]for(int i=1;i<=vNum;i++)for(int j=1;j<=i&&j<=pNum;j++){int min=INF;int chose=0;//存储选择最小值对应的kfor(int 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]; chose=k;}}dp[i][j]=min;flag[i][j]=chose;} cout<<dp[vNum][pNum]<<endl;}void PrintPostOffice(int vNum,int pNum){if((0==pNum)||pNum>vNum) return;else{ int k=flag[vNum][pNum]; PrintPostOffice(k,pNum-1); cout<<vPos[(k+1+vNum)/2]<<" ";}}int main(){cin>>vNum>>pNum;for(int i=1;i<=vNum;i++)cin>>vPos[i];solve();cout<<"选择的邮件序列"<<endl;PrintPostOffice(vNum,pNum);}
- 动态规划入门(四)DP 基本思想与实现
- 动态规划入门(四)DP 基本思想 具体实现 经典题目 POJ1160 POJ1037
- 动态规划入门(一) DP 基本思想
- 动态规划入门(一) DP 基本思想 具体实现 经典题目
- 动态规划入门(二)DP 基本思想 具体实现 经典题目 POJ1088 POJ1163 POJ1050
- 动态规划入门(三)DP 基本思想 具体实现 经典题目 POJ1159 POJ1458 POJ1141
- 动态规划入门(二)DP 基本思想 具体实现 经典题目 POJ1088
- 【算法与实现】动态规划(基本思想)
- 动态规划基本思想
- 动态规划-基本思想
- DP(动态规划)的基本思想和基本步骤(zz)
- 动态规划入门(四)
- 动态规划(DM)的基本思想
- (一)、动态规划的基本思想
- (一)、动态规划的基本思想
- DP动态规划思想讲解
- 动态规划的基本思想
- 动态规划的基本思想
- A. Initial Bet
- 设计模式学习笔记-适配器模式
- 设计模式转载好文
- SIM900A 发送AT+CSTT 总是 返回Error的原因分析
- SQLSERVER连接问题
- 动态规划入门(四)DP 基本思想与实现
- linux/android uevent
- 这是函数声明还是变量声明
- 男人25岁后应该明白的道理
- RAC
- Shell脚本入门(四) - 读取键盘输入
- Tomcat源码之Connector (1)
- 郝华奇:穿戴式设备的用户体验设计
- PHP-redis中文文档