1201动态规划.docx

上传人:b****2 文档编号:2235167 上传时间:2022-10-28 格式:DOCX 页数:37 大小:67.12KB
下载 相关 举报
1201动态规划.docx_第1页
第1页 / 共37页
1201动态规划.docx_第2页
第2页 / 共37页
1201动态规划.docx_第3页
第3页 / 共37页
1201动态规划.docx_第4页
第4页 / 共37页
1201动态规划.docx_第5页
第5页 / 共37页
点击查看更多>>
下载资源
资源描述

1201动态规划.docx

《1201动态规划.docx》由会员分享,可在线阅读,更多相关《1201动态规划.docx(37页珍藏版)》请在冰豆网上搜索。

1201动态规划.docx

1201动态规划

第3章动态规划

如果问题是由重叠的子问题所构成的,就可以用动态规划技术来解决。

一般来说,这样的子问题出现在对给定问题求解的递推关系中,这个递推关系包含了相同类型的更小子问题的解。

动态规划建议,与其对重叠的子问题一次又一次地求解,还不如对每个较小的子问题只求一次并把结果记录在表中,这样就可以从表中得到原始问题的解。

3.1Fibonacci数列问题

求Fibonacci数列的第n项。

f(n)=f(n-1)+f(n-2)

f

(1)=1,f

(2)=1

(1)直接递归法,此法会大量重复计算子问题的结果

intFib(intn){

if(n==1||n==2)return1;

returnFib(n-1)+Fib(n-2);

}

(2)动态规划方法,使用数组存储每个子问题的结果

intf[100];

intFib(intn){

f[1]=f[2]=1;

for(inti=3;i<=n;i++)

f[i]=f[i-1]+f[i-2];

returnf[n];

}

(3)改进,只存储最后2个元素的值,避免使用数组

intFib(intn){

intf,f1,f2;

f1=f2=1;

for(inti=3;i<=n;i++){

f=f1+f2;

f1=f2;

f2=f;

}

returnf;

}

(4)备忘录方法,使用递归方法,但利用数组存储来避免重复计算子问题

intf[100];

intFib(intn){

if(f[n]>0)returnf[n];

if(n==1||n==2)return1;

f[n]=Fib(n-1)+Fib(n-2);

returnf[n];

}

 

3.2计算二项式系数

二项式公式为

(a+b)n=C(n,0)an+…+C(n,k)an-kbk+…+C(n,n)bn

其中C(n,k)为二项式系数

(a+b)n-1=C(n-1,0)an-1+…+C(n-1,k-1)an-kbk-1+C(n-1,k)an-k-1bk+…+C(n-1,n-1)bn-1

由(a+b)n=(a+b)(a+b)n-1可得:

(1)计算二项式系数的递归函数为

intC(intn,intk){

if(k==0||n==k)return1;

returnC(n-1,k-1)+C(n-1,k);

}

但用这种递归方法效率非常低(计算C(32,20)都用了好几秒钟)。

(2)用动态规划来求二项式系数

intm[100][100];

intC(intn,intk){

for(inti=0;i<=n;i++)

m[i][0]=m[i][i]=1;

for(inti=1;i<=n;i++)

for(intj=1;j

m[i][j]=m[i-1][j-1]+m[i][j-1];

returnm[n][k];

}

(3)用备忘录方法来求二项式系数

intm[100][100]={0};

intC(intn,intk){

if(m[n][k]==0)

if(k==0||n==k)m[n][k]=1;

elsem[n][k]=C(n-1,k-1)+C(n-1,k);

returnm[n][k];

}

 

3.3整数划分问题

1、把一个正整数n分成任意个正整数的和,有多少种分法?

例如正整数6有如下11种不同的划分:

6;

5+1;

4+2,4+1+1;

3+3,3+2+1,3+1+1+1;

2+2+2,2+2+1+1,2+1+1+1+1;

1+1+1+1+1+1。

设f(n,m)表示整数n的划分中,每个数不大于m的划分数。

则划分数可以分为两种情况:

a.划分中每个数都小于m。

划分数为f(n,m-1)

b.划分中至少有一个数为m。

就相当于把n-m进行划分,故划分数为f(n-m,m)

于是:

f(n,m)=f(n,m-1) +f(n-m,m)

其它条件为:

f(0,m)=1;f(1,m)=1;f(n,1)=1;

程序为

intf(intn,intm){

if(m==1||n==1||n==0)return1;

if(n

returnf(n,m-1)+f(n-m,m);

}

动态规划方法

intmain(){

inta[11][11],n;

for(inti=1;i<=10;i++)

a[i][1]=a[1][i]=a[0][i]=1;

for(inti=2;i<=10;i++){

for(intj=2;j<=i;j++)

a[i][j]=a[i][j-1]+a[i-j][j];

for(intj=i+1;j<=10;j++)

a[i][j]=a[i][i];

}

cin>>n;

cout<

}

 

2、把一个正整数n分成m个正整数的和,有多少种分法?

设f(n,m)把n分成m个正整数的和的分法。

则划分数可以分为两种情况:

a.划分中每个数都>=2。

相当于先拿出m个1,将剩下的再分,划分数为f(n-m,m)

b.划分中至少有一个数为1。

相当于把n-1分成m-1个数,故划分数为f(n-1,m-1)

于是:

f(n,m)=f(n-1,m-1)+f(n-m,m)

其它条件为:

f(n,1)=1;当n

程序为

intf(intn,intm){

if(m==1)return1;

if(n

returnf(n-1,m-1)+f(n-m,m);

}

3、把一个正整数n分成不超过m个正整数的和,有多少种分法?

设f(n,m)表示最多用m个整数来划分n,可分为两种情况:

a.把n分成不超过m-1个正整数的和。

划分数为f(n,m-1)

b.把n分成正好m个正整数的和。

就相当于先拿出m个1,再把n-m分成不超过m个正整数的和,故划分数为f(n-m,m)

于是:

f(n,m)=f(n,m-1) +f(n-m,m)

此题居然和“1、用不大于m的数去划分n”完全等价。

4、“2、把正整数n分成m个正整数的和”可以转换为“把正整数n分成不超过m个正整数的和”,只需先拿出m个1,然后再将n-m分成不超过m个正整数的和。

f2(n,m)=f3(n-m,m)

 

3.40-1背包问题

0-1背包问题:

给定n种物品和一个背包,物品i的重量为wi,其价值为vi,背包的承重量为c。

问如何选择物品装入背包,使得物品的总价值最大。

物品的重量为:

w={w1,w2,…,wi,…,wn},价值为:

v={v1,v2,…,vi,…,vn},背包容量为c。

设f(i,j)表示剩余容量为j,剩余物品为i,i+1,…,n时的最优解的值,则有

例:

设n=5,c=10,w={2,2,6,5,4},v={6,3,5,4,6},问题求解过程示意图如下:

例1:

0/1背包问题的递归解法

#include

usingnamespacestd;

intn=5,w[]={0,2,2,6,5,4},v[]={0,6,3,5,4,6};

intf(inti,intj){

if(i==n)returnj

0:

v[n];

if(j

returnmax(f(i+1,j),f(i+1,j-w[i])+v[i]);

}

例2:

用动态规划解决0/1背包问题

设n=5,c=10,w={2,2,6,5,4},v={6,3,5,4,6}

w

v

0

1

2

3

4

5

6

7

8

9

10

1

2

6

15

2

2

3

0

0

3

3

6

6

9

9

9

10

11

3

6

5

0

0

0

0

6

6

6

6

6

10

11

4

5

4

0

0

0

0

6

6

6

6

6

10

10

5

4

6

0

0

0

0

6

6

6

6

6

6

6

#include

usingnamespacestd;

floatm[100][100];

voidKnapsack(floatv[],intw[],intc,intn){

inti,j,jmax;

jmax=min(w[n]-1,c);

for(j=0;j<=jmax;j++)m[n][j]=0;

for(j=w[n];j<=c;j++)m[n][j]=v[n];

for(i=n-1;i>1;i--){

jmax=min(w[i]-1,c);

for(j=0;j<=jmax;j++)m[i][j]=m[i+1][j];

for(j=w[i];j<=c;j++)

m[i][j]=max(m[i+1][j],m[i+1][j-w[i]]+v[i]);

}

m[1][c]=m[2][c];

if(c>=w[1])

m[1][c]=max(m[1][c],m[2][c-w[1]]+v[1]);

}

voidtraceback(intw[],intc,intn,intx[]){

for(inti=1;i

if(m[i][c]==m[i+1][c]){

x[i]=0;

}else{

x[i]=1;

c-=w[i];

}

x[n]=m[n][c]?

1:

0;

}

intmain(){

floatv[]={0,6,3,5,4,6};

intc=10,n=5,w[]={0,2,2,6,5,4},x[6];

Knapsack(v,w,c,n);

traceback(w,c,n,x);

cout<<"themaxvalueis:

"<

for(inti=1;i<=n;i++)

cout<

}

例3:

0/1背包问题的备忘录解法

#include

usingnamespacestd;

floatm[100][100];

intn=5,w

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 人文社科 > 法律资料

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1