《算法导论》第15章
动态规划与分治算法
相同:都是通过组合子问题的解而解决整个问题。
不同:分治算法是将问题划分成一些独立的子问题,递归地求解各个子问题,然后合并子问题的解而得到原问题的解。
动态规划适用于子问题不是独立的情况,也就是各个子问题包含公共的子子问题。在这种情况下,若用分治算法则会做许多不必要的工作,即重复地求解公共的子子问 题。动态规划算法对每个重复的子子问题只求解一次,将其结果保存在一张表中,从而避免每次遇到各个子问题时重新计算答案。
动态规划与贪心算法
贪心算法与动态规划有很多相似之处。贪心算法适用的问题也具有最优子结构。
区别:在贪心算法中是以自顶向下的方式使用最优子结构的。贪心算法会先做选择,在当时看来是最优的选择,然后再求解一个结果子问题,而不是先寻找子问题的最优解,然后再做选择。
在做poj1015时遇到需要采用动态规划来解。刚看完题目,不知道要用动态规划,对动态规划也不是很了解,想了一下,实在没思路,就上网搜了一下,各位大神都是用动态规划。实在看不懂呀,只好看一下《算法导论》,算是有点明白了,再来看各位大神的代码,还是觉得有些混乱呀~~先放放啦,动态规划,动态规划呀,对于我来说太难了~~
参考代码:http://www.cppblog.com/mythit/archive/2009/06/23/88378.html
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define MAX_N 201
int plus[MAX_N];//保存每个人的p和d之和,plus[0]未使用
int sub[MAX_N];//保存每个人的d-p,sub[0]未使用
int f[21][801];//f[j][k]表示在选m个人中的第j个人的时候使所有已选中的人的d,p差为k时,所能获得的p,d最大和。因为1=<m<=20,所以第一维取20+1;因为每个人的d和p在[0,20]内,所以m个人的D(J)-P(J)在[-20*m,20*m]内,最多有801种取值。因为下标非负,所以需要加上m*20进行转化
int path[21][801];//在f[j][k]中选择的第j个人的编号保存在path[j][k]中
int res[21];
int cmp(const void *a,const void *b)
{
return *(int*)a-*(int*)b;
}
int main()
{
int i, j, k, a, b;
int n,m,case_num=0;
int p,d;
int width;
while(1)
{
scanf("%d %d", &n, &m);
if(n==0 && m==0)
break;
for(i=1; i<=n; i++)
{
scanf("%d %d",&p, &d);
sub[i] = d-p;
plus[i] = d+p;
}
//scanf("\n");
case_num++;
memset(f, -1, sizeof(f));
memset(path, 0, sizeof(path));
width = m*20;
f[0][width] = 0;
for(j=0; j<m; j++)
{
for(k=0; k<=2*width; k++)
{
if(f[j][k]>=0)//从f[0][width]开始
{
for(i=1; i<=n; i++)
{
if(f[j+1][k+sub[i]]<f[j][k]+plus[i])//
{
a = j;
b = k;
while(a>0 && path[a][b]!=i)//判断i有没有被选过
{
b -= sub[path[a][b]];
a--;
}
if(a==0)//i没有被选过
{
f[j+1][k+sub[i]] = f[j][k]+plus[i];
path[j+1][k+sub[i]] = i;
}
}
}
}
}
}
for(j=0; f[m][width+j]<0&&f[m][width-j]<0;j++);//寻找绝对值最小的
k=f[m][width+j]>f[m][width-j]?width+j:width-j;//寻找绝对值最小的和最大的
printf("Jury #%d\n",case_num);
printf("Best jury has value %d for prosecution and value %d for defence:\n", (f[m][k]-k+width)/2,(f[m][k]+k-width)/2);
for(i=1;i<=m;i++)
{
res[i]=path[m-i+1][k];
k-=sub[res[i]];
}
qsort(res+1,m,sizeof(res[0]),cmp);
for(i=1;i<=m;i++)
printf(" %d",res[i]);
printf("\n\n");
}
return 0;
}