《算法導論》第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;
}