动态规划程序设计是对解最优化问题的一种途径、一种方法,而不是一种特殊算法。不象搜索或数值计算那样,具有一个标准的数学表达式和明确清晰的解题方法。动态规划程序设计往往是针对一种最优化问题,由于各种问题的性质不同,确定最优解的条件也互不相同,因而动态规划的设计方法对不同的问题,有各具特色的解题方法,而不存在一种万能的动态规划算法,可以解决各类最优化问题。因此读者在学习时,除了要对基本概念和方法正确理解外,必须具体问题具体分析处理,以丰富的想象力去建立模型,用创造性的技巧去求解。我们也可以通过对若干有代表性的问题的动态规划算法进行分析、讨论,逐渐学会并掌握这一设计方法。

      所以dp算法的难点在于找状态转移方程。在poj做了一些动态规划的题目,在这里做个总结。


1、poj 1160

a 题目描述:

 在v个村庄(村庄呈直线分布)设置p个邮局,使各个村庄到邮局的 总距离最短。

b 解题方案:

 cost[v][p]  代表在v个村庄建立p个邮局的最短距离

 dis[v][v]   ;dis[i][j] 表示在第i个村庄和第j个村庄之间建立一个邮局,显然,这个邮局应该建在i和j的中间。

c 状态转移方程:

 cost[v][p] = cost[i][p-1] + dis[i+1][v] // p<=i<=v;



2、poj 1260

a 问题描述:

 有c个种类的珠宝,每个种类的珠宝有需要购买的个数n和相应的价值p,需要购买某一种需要花费(n+10)*p; 购买时,低质量的珠宝可以用高质量的珠宝代替;为了最终花费的钱最少。

b 解题方案:

 dp[c];dp[i]表示到第i中珠宝时花费的最少钱

 num[c];num[i]表示从0到i之间质量的珠宝的所有数目

c 状态转移方程:

 dp[i] = (num[i] + 10)*p[i]

 dp[i] = min(dp[i],dp[j]+(num[i] - num[j] + 10)*p[i]) // 0<=j<i


3、poj 1276

a 问题描述:

 有n中钱币,每种有ai张,价值di;要求凑出m价值,求凑出的最接近m的值。

b 解决方法:

 这是个多重背包问题,可以将重复价值的纸币加起来,或者直接当成一个个体。这样就变成01背包了。

c 状态转移方程:

 for (i = 1; i<=count; i++) //count为有多少张钱币,v[i]对应第i张钱币的价值

       for (k = m; k>=v[i]; k--) // m 为最终要拼出的价值

          opt[k] = opt[k] | opt[k - v[i]]; //如果能拼出k,则opt[k]=1;



4、poj 1745

a 问题描述

 给出一列数,可以在相邻两个数之间执行相加或者相减的操作,得出的所有结果中是否能被k整除。

b 解决方法

 C[10001][101]; C[i][j]表示i个数字的运算结果sum, sum % k = j,若存在则为1,否则为0

c 状态转移方程

 C[i][j] = C[i-1][(j-a[i])%k] | c[i-1][(j+a[i])%k]; //这里需要防止 j-a[i] 和 j+a[i]为负数,所以还需做一些操作,为了简便,这里就不写了


5、poj 1837

a 问题描述

 天平平衡问题,有G砝码,每个砝码重量为g[i],需要将这n个砝码挂在天平C个刻度上(c[i]表示刻度达标),要求天平最终要平衡。天平左边的刻度用负数表示,右边的刻度用正数表示。求平衡的方法有几种。

b 解决方法

 因为有负数存在,所以需要做偏移,最大偏移量为 :M = 砝码的最大重量*最大尺度*砝码的最大个数。

 w[i][j] //表示挂上第i个砝码后,力矩为j的几种方法

c 状态转移

 for(i=1;i<=G;i++) //G个砝码

      for(j=1;j<=C;j++)//C个刻度

         for(k=0;k<7501;k++) //力矩

         {

                w[i][k+g[i]*c[j]] += w[i-1][k]; //将第i个砝码挂在第j个刻度上,力矩的变化

         }

 cout<<w[G][3500]<<endl;