动态规划总结经典题目(经典中的经典)

动态规划总结经典题目(经典中的经典)
动态规划总结经典题目(经典中的经典)

动态规划总结——经典问题总结

本文着重讨论状态是如何表示,以及方程是怎样表示的。当然,还附上关键的,有可能作为模板的代码段。但有的代码的实现是优化版的。

经典问题总结

最长上升子序列(LIS)

问题描述如下:

设L=是n个不同的实数的序列,L的递增子序列是这样一个子序列Lin=,其中k1

这里采用的是逆向思维的方法,从最后一个开始想起,即先从A[N](A数组是存放数据的数组,下同)开始,则只有长度为1的子序列,到A[N-1]时就有两种情况,如果a[n-1] < a[n] 则存在长度为2的不下降子序列 a[n-1],a[n];如果a[n-1] > a[n] 则存在长度为1的不下降子序列a[n-1]或者a[n]。

有了以上的思想,DP方程就呼之欲出了(这里是顺序推的,不是逆序的):

DP[I]=MAX(1,DP[J]+1) J=0,1,...,I-1

但这样的想法实现起来是)O(n^2)的。本题还有更好的解法,就是O(n*logn)。利用了长升子序列的性质来优化,以下是优化版的代码:

//最长不降子序

const int SIZE=500001;

int data[SIZE];

int dp[SIZE];

//返回值是最长不降子序列的最大长度,复杂度O(N*logN)

int LCS(int n) { //N是DATA数组的长度,下标从1开始

int len(1),low,high,mid,i;

dp[1]=data[1];

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

low=1;

high=len;

while( low<=high ) { //二分

mid=(low+high)/2;

if( data[i]>dp[mid] ) {

low=mid+1;

}

else {

high=mid-1;

}

}

dp[low]=data[i];

if( low>len ) {

++len;

}

}

return len;}

最长公共子序列(LCS)

给出两个字符串a, b,求它们的最长、连续的公共字串。

这很容易就想到以DP[I][J]表示A串匹配到I,B串匹配到J时的最大长度。则:

0 I==0 || J==0

DP[I][J]=DP[I-1][J-1]+ 1 A[I]==B[J]

MAX(DP[I-1][J],DP[I][J-1])不是以上情况

但这样实现起来的空间复杂度为O(n^2),而上面的方程只与第I-1行有关,所以可以用两个一维数组来代替。以下是代码:

//最长公共子序列

const int SIZE=1001;

int dp[2][SIZE]; //两个一维数组

//输入两个字符串,返回最大的长度

int LCS(const string& a,const string& b) {

int i,j,flag;

memset(dp,0,sizeof(dp));

flag=1;

for(i=1;i<=a.size();++i) {

for(j=1;j<=b.size();++j) {

if( a[i-1]==b[j-1] ) dp[flag][j]=dp[1-flag][j-1]+1;

else dp[flag][j]=MAX(dp[flag][j-1],dp[1-flag][j]);

}

flag=1-flag;

}

return dp[1-flag][b.size()];

}

01背包

有N件物品和一个容量为V的背包。第i件物品的大小是c[i],价值是w[i]。求解将哪些物品装入背包可使价值总和最大。

用DP[I][J] 表示前I件物品放入一个容量为J的背包可以获得的最大价值。则

DP[I][J]= DP[I-1][J] ,J

MAX(DP[I-1][J],DP[I-1][J-C[I]]+W[I]) , J>=C[I]

这样实现的空间复杂度为O(VN),实际上可以优化到O(V)。以下是代码:

const int MAXW=13000; //最大重量

const int MAXN=3450; //最大物品数量

int c[MAXN]; //物品的存放要从下标1开始

int w[MAXN]; //物品的存放要从下标1开始

int dp[MAXW];

//不需要将背包装满,则将DP数组全部初始化为0

//要将背包装满,则初始化为DP[0]=0,DP[1]…DP[V]=-1(即非法状态)

int Packet(int n,int v) {

int i,j;

memset(dp,0,sizeof(dp));

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

for(j=v;j>=c[i];--j) { //这里是倒序,别弄错了

dp[j]=MAX(dp[j],dp[j-c[i]]+w[i]);

}

}

return dp[v];}

完全背包问题

有N种物品和一个容量为V的背包,每种物品都有无限件可用。第i种物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

很容易可以得到这种状态表示:用DP[I][J] 表示前I件物品放入一个容量为J的背包可以获得的最大价值。则

DP[I][J]=MAX(DP[I-1][J],DP[I-1][J-K*C[I]]+K*W[I]) 0<=K*C[I]<=J

这样的复杂度是O(V*Σ(V/c[i]))

有更好的做法,那就是利用01背包的优化原理。在优化的代码中,之所以第二重循环是倒序,是为了防止重复拿,那么只要将其变为顺序即可以重复取。代码就不给了。

多重背包问题

有N种物品和一个容量为V的背包。第i种物品最多有n[i]件可用,每件费用是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

这题仍然可以用到上一题的思想,DP表示状态与上面的相同。方程为:

DP[I][J]=MAX(DP[I-1][J],DP[I-1][J-K*C[I]]+K*W[I])

不同的是K的范围,0<=K<=N[I] && 0<=K*C[I]<=J

这样的复杂度为O(V*Σn[i])。

有更好的想法就是先用二进制来划分。将第i种物品分成若干件物品,其中每件物品有一个系数,这件物品的费用和价值均是原来的费用和价值乘以这个系数。使这些系数分别为

1,2,4,...,2^(k-1),n[i]-2^k+1,且k是满足n[i]-2^k+1>0的最大整数。然后用01背包做,这样的复杂度为O(V*Σlog n[i])。关键代码:

const int SIZE=1001;

int dp[SIZE];

int num[SIZE],c[SIZE],w[SIZE]; //num[i]是I物品的件数,C[I]是费用,W[I]是价值

int MultiPack(int n,int v) { //存入参数,N是物品种类数,V是背包容量

int i,j,k;

memset(dp,0,sizeof(dp));

for(i=1;i<=n;++i) { //存放物品的数组下标从1开始

if( c[i]*num[i]>=v ) {

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

dp[j]=MAX(dp[j],dp[j-c[i]]+w[i]);

}

}

else { //使用二进制划分

k=1;

while( k

for(j=v;j>=k*c[i];--j) {

dp[j]=MAX(dp[j],dp[j-k*c[i]]+k*w[i]);

}

num[i]-=k;

k*=2;

}

for(j=v;j>=num[i]*c[i];--j) {

dp[j]=MAX(dp[j],dp[j-num[i]*c[i]]+num[i]*w[i]);

}

}

}

return dp[v];

}

状态表示总结

一维的状态表示

DP的表示形式通常为:DP[I]表示取到第I个/种物品时的最优值。DP方程的形式:DP[I]=MAX(DP[I],DP[J]+P[I])其中0<=J

DP[I]=DP[I-1]+P[I](即只与I-1有关)

有一些题可能要将一些额外的东西也认为是物品。如HDU2059龟兔赛跑这题,需要将开始点和终点也认为是加油站,然后才以DP[I]表示到第I个加油站并加满油的最短时间。

有一些题可以将看似二维的情况转化为一维的情况来做。如HDU 1081这题。大意是给出一个含有正数和负数的N阶矩阵,求一个子矩阵使得子矩阵内所有数的和最大。这样的题可以将几行合并为一行做。即枚举就将第I行到第J行合并为一行,然后再用DP[K]=MAX(DP[K-1],0)+ARR[K],K是表示第K列。

有一些题是DP与暴力相结合,如POJ 3267 The Cow Lexicon这题。大意是给出一个长的字符串,还有若干个短的字符串,问长字符中至少要删除几个字符才能使得长字符串中的子字符串都与某个短字符串相对应。dp[i]表示从I到LEN-1需要删除的最少字符串数,则dp[i]=min(dp[i+1]+1,dp[k]+del)其中dp[i+1]+1是没有找到匹配的情况,dp[k]+del是有匹配的情况,K表示从I开始匹配,到匹配完后的最后一个字符的位置,DEL表示在匹配过程中要删除的字符数。由于方程的特点,要从最后一个字符向第一个字符推去。中间要删除的字符数用暴力找出。

有一些题用DP来枚举全部的范围,如POJ 1925 Spiderman这题。用DP[I]表示到达这个位置的最小跳数。其中DP数组为dp[1000005],这是可能跳到的全部范围。

二维状态表示

通常是用来处理两种事物。DP[I][J]通常表示A的前I个和B的前J个XX的最优值。

DP方程之一:DP[I][J]=MAX(DP[I-1][J-1]+P[XX],DP[I][J-1]+P[YY],

DP[I-1][J]+P[ZZ])这里的XX,YY,ZZ是表示某某状态得到的结果。

DP方程之二:DP[I][J]=MAX(DP[I][J],DP[I-1][K]+P[I][J]),其中0<=K

DP方程之三:DP[I][J]=MAX(DP[I+1][J]+P[XX],DP[I][J-1]+P[YY])

对第三种DP方程举个例:POJ 3280 Cheapest Palindrome这题。大意是给出一个字符串,你可在任意位置增加或删除字符,每增加或删除一个字符都有一个对应的代价,求将其变为回文串的最小代价。以dp[i][j]表示从i到j要变成回文字符串的最小代价,则

dp[i][j] = min{ dp[i+1][j] + {去掉X的代价},dp[i+1][j] + {加上X的代价},

dp[i][j-1]+ {去掉Y的代价},dp[i][j-1] +{加上Y的代价}};

算DP[I][J]时,要知道DP[I+1][J]的值,对于这类DP其实现方法如下所示:for(t=1;t

for(i=1;i

if( i+t<=len ) {

j=i+t;

//do your work

}

}

}

有一些题看似一维,可将之变为二维。如:POJ1159 Palindrome这题。大意是给出一个字符,求将其变为回文串要加入的最少字符数。得到字符串后,再构造一个逆串,然后求其LCS。最后将字符串长度减去LCS数就是结果。

有时可以将DP与HASH相结合。如:POJ 1054 The Troublesome Frog这题。大意是在一个坐标系中给出N个点,求找出以哪两点作一条直线经过的点数最多。以DP[I][J]表示过第J点和第I点的直线一共经过的点数。DP[I][J]=(DP[J][INDEX]+1,-INF),先算出INDEX这点的坐标,然后用哈希查找,如果找到,则执行

DP[J][INDEX]+1,如果找不到则用-INF表示不存在。

对于整除类型的题,如果要用DP做,那么其中有一维通常是佘数。如:POJ 1745Divisibility这题,dp[i][j]表示对前I个数进行了处理,余数为J的情况

带偏移的状态表示

DP的表示形式通常为:DP[I][J]表示到第I个XX时,YY与ZZ之差为J时的最优值。例如:POJ 1837这题。

题目大意:给出天平c个挂钩的位置,然后给出g个物品的质量,将物品挂在天平上,问使天平平衡的方法有几种。

思想:用l[i]表示第i个点的x坐标值,用w[i]表示第i个砝码的重量,用dp[i][j]表示加了i个砝码,两边力矩之差为j的可能方法数,则本题只要计算出dp[i][0],即最终力矩差为0的方法数即可。由于质量差可能为负,这里加上一个偏移量,考虑原题的数据可知,要想平衡,则一边力矩至多为15*25*10=3750,故每个j加上3750。状态转移方程:dp[i+1][k+w[i]*l[j]]+= dp[i][k],i=0~g,j=0~c,k=0~7500。输出结果:dp[w][3750]

动态规划变态总结by zeus

1:Pku acm 1163 the Triangle

2:Pku acm 1953 World Cup Noise //说白了就是斐波那切数列

3:Pku acm 1458 Common Subsequence Lcs

4:Pku acm 2250 Compromise记录路径的lcs

5:Pku acm 1159 Palindrome 回文串

6:Pku acm 1080 Humman Gene Function

7:Pku acm 2192 Zipper 判断2个字符串能否组成1个字符串

8:Pku acm 3356 AGTC 一个字符串到另一个的最小步骤

9:Pku acm 1887 Testing the CATCHER最长下降子序列

10:Pku acm 2533 Longest Ordered Subsequence最长上升子序列

11:Pku acm 1631 Bridging signals最长上升子序列的加强版….二分法

12:Pku acm 1157 LITTLE SHOP OF FLOWERS

13:Pku acm 1088 滑雪

14:Pku 1050 To the Max

15:Pku 1050 To the Max最大线段和的加强板…..二维的16:Pku 1014 dividing

17: Pku acm 1160 post office

18: pku acm 1015 Jury Compromise

19: hdoj 2546饭卡

20:pku 1837 Balance

21: pku 3267 The Cow Lexicon

22:Pku 1742 Coins

//走塔....经典的dp

#include "iostream"

using namespace std;

int max(int a,int b)

{

return a>b?a:b;

}

int main()

{

int n,i,j;

int a[100][100];

int f[100];

while(scanf("%d",&n)>0)

{

for(i=0;i

for(j=0;j<=i;j++)

{

scanf("%d",&a[i][j]);

if(i==n-1)

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

}

for(i=n-2;i>=0;i--)

{

for(j=0;j<=n-1;j++)

if(f[j]>f[j+1])

f[j]=f[j]+a[i][j];

else

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

}

printf("%d\n",f[0]);

}

system("pause");

}

2:Pku acm 1953 World Cup Noise //说白了就是斐波那切数列

#include "iostream"

using namespace std;

int main()

{

int n,m;

int i;

int f[100];

f[0]=2;

f[1]=3;

scanf("%d",&n);

for(i=2;i<100;i++)

{

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

}

for(i=0;i

{

scanf("%d",&m);

{

printf("Scenario #%d:\n%d\n\n",i+1,f[m-1]); }

}

}

3:Pku acm 1458 Common Subsequence Lcs经典

#include "iostream"

#include "cstring"

using namespace std;

int setmax(int a,int b)

{

if(a>b)

return a;

else return b;

}

int f[8100][8100];

main()

{

char s1[800];

char s2[800];

int i,j;

int sl1,sl2;

while(scanf("%s %s",&s1,&s2)!=EOF)

{

sl1=strlen(s1);

sl2=strlen(s2);

for(i=0;i

{

f[0][i]=0;

f[i][0]=0;

}

for(i=1;i

for(j=1;j

{

if(s1[i-1]==s2[j-1])

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

else

f[i][j]=setmax(f[i-1][j],f[i][j-1]);

}

printf("%d\n",f[i-1][j-1]);

}

}

4:Pku acm 2250 Compromise记录路径的lcs

#include "iostream"

#include "string"

using namespace std;

#define N 100

struct node

{

string s;

}s1[N],s2[N];

int f[N][N];

int path[N][N];

string temp;

int flag;

void lcs(int i,int j)

{

if(i==0||j==0) return ;

if(path[i][j]==1) {

lcs(i-1,j-1);

{

if(flag!=1){

cout<

flag=1;}

else

cout<

}

else

if(path[i][j]==2) lcs(i-1,j);

else lcs(i,j-1);

}

int main()

{

int i=0,j;

int len1,len2;

while(cin>>s1[0].s)

{

memset(f,0,sizeof(f));

i=1;

while(1){

cin>>temp;

if(temp=="#") break;

s1[i++].s=temp;

}

len1=i;

i=0;

while(1){

cin>>temp;

if(temp=="#") break;

s2[i++].s=temp;

}

len2=i;

memset(path,0,sizeof(path));

for(i=0;i<=len1;i++)

for(j=0;j<=len2;j++)

if(i==j) f[i][j]=1;

for(i=1;i<=len1;i++)

for(j=1;j<=len2;j++)

{

if(s1[i-1].s==s2[j-1].s)

{

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

path[i][j]=1;

}

else if(f[i-1][j]>=f[i][j-1])

{

f[i][j]=f[i-1][j];

path[i][j]=2;

}

else

{

f[i][j]=f[i][j-1];

path[i][j]=3;

}

}

flag=1;

lcs(len1,len2);

cout<

}

}

5:Pku acm 1159 Palindrome 回文串

带有些许优化的lcs

#include "iostream"

#include "string"

#include "algorithm"

using namespace std;

int a[5005],b[5005];

int c[3],d[3];

string s1,s2;

int main()

{

int m,n=0;

int i,j;

while(cin>>n)

{

if(n==0) break;

cin>>s1;

s2=s1;

reverse(s2.begin(),s2.end());

memset(a,0,sizeof(a));

memset(b,0,sizeof(b));

for(i=0;i

{

b[0]=0;

for(j=0;j

{

if(s1[i]==s2[j])

{

b[j+1]=a[j]+1;

}

else if(b[j]>a[j+1])

{

b[j+1]=b[j];

}

else if(b[j]

{

b[j+1]=a[j+1];

}

}

for(j=0;j<=n;j++)

a[j]=b[j];

}

printf("%d\n",n-b[n]);

}

}

6:Pku acm 1080 Humman Gene Function

#include "iostream"

using namespace std;

int f[250][250];

int g[250][250];

char s1[180];

char s2[180];

int maxnum(int x,int y,int z)

{

int zz= x>y?x:y;

return zz>z?zz:z;

}

void make()

{

f[1][1]=5;f[1][2]=-1;f[1][3]=-2;f[1][4]=-1;f[1][5]=-3;

f[2][1]=-1;f[2][2]=5;f[2][3]=-3;f[2][4]=-2;f[2][5]=-4;

f[3][1]=-2;f[3][2]=-3;f[3][3]=5;f[3][4]=-2;f[3][5]=-2;

f[4][1]=-1;f[4][2]=-2;f[4][3]=-2;f[4][4]=5;f[4][5]=-1;

f[5][1]=-3;f[5][2]=-4;f[5][3]=-2;f[5][4]=-1;f[5][5]=-99999; }

int sw(char ch)

{

if(ch=='A') return 1;

else if(ch=='C') return 2;

else if(ch=='G') return 3;

else if(ch=='T') return 4;

else if(ch=='-') return 5;

}

int find(char ch1,char ch2)

{

return f[sw(ch1)][sw(ch2)];

}

int main()

{

make();

int sl1,sl2,i,j,m;

memset(g,0,sizeof(0));

cin>>m;

while(m--)

{

cin>>sl1;

cin>>s1;

cin>>sl2;

cin>>s2;

for(i=1;i<=sl2;i++)

g[0][i] = g[0][i-1]+find('-',s2[i-1]);

for(i=1;i<=sl1;i++)

g[i][0] = g[i-1][0]+find(s1[i-1],'-');

for(i=1;i<=sl1;i++)

for(j=1;j<=sl2;j++)

{

g[i][j]=maxnum(g[i][j-1]+find('-',s2[j-1]),g[i-1][j]+find(s1[i-1],'-'),g[i-1][j-1]+find(s1[i-1],s2[j-1]));

}

cout<

}

}

7:Pku acm 2192 Zipper 判断2个字符串能否组成1个字符串

//用动态规划解决,ok[i][j]表示str1长度为i的前缀和str2长度为j的后缀能否组成目标中str中长度为i+j的前缀串

#include "iostream"

using namespace std;

int i,j,n;

int sl1,sl2,sl3;

char s1[500],s2[500],s3[500];

int f[500][500];

int main()

{

int count=0;

scanf("%d",&n);

while(n--)

{count++;

memset(f,0,sizeof(f));

scanf("%s %s %s",s1,s2,s3);

sl1=strlen(s1);

sl2=strlen(s2);

sl3=strlen(s3);

for(j=0;j

{

if(s1[j]==s3[j])

f[j+1][0]=1;

else

break;

}

for(i=0;i

{

if(s2[i]==s3[i])

f[0][i+1]=1;

else

break;

}

for(i=0;i<=sl1;i++)

for(j=0;j<=sl2;j++)

{

if(!(i==0&&j==0))

if(s1[i]==s3[i+j]&&f[i][j]==1)

f[i+1][j]=1;

if(s2[j]==s3[i+j]&&f[i][j]==1)

f[i][j+1]=1;

}

printf("Data set %d: ",count);

if(f[sl1][sl2]==1)

printf("yes\n");

else

printf("no\n");

}

}

8:Pku acm 3356 AGTC 一个字符串到另一个的最小步骤

#include "iostream"

#include "string"

using namespace std;

int setmin(int x,int y,int z)

{

int xx=x>y?y:x;

return xx>z?z:xx;

}

string s1,s2;

int f[1005][1005];

int main()

{

int n,m;

int i,j;

while(cin>>n)

{

cin>>s1;

cin>>m;

cin>>s2;

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

f[i][0]=i;

for(i=0;i<=m;i++)

f[0][i]=i;

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

for(j=1;j<=m;j++)

{

if(s1[i-1]==s2[j-1])

f[i][j]=setmin(f[i-1][j]+1,f[i][j-1]+1,f[i-1][j-1]);

else

f[i][j]=setmin(f[i-1][j]+1,f[i][j-1]+1,f[i-1][j-1]+1);

}

cout<

}

}

9:Pku acm 1887 Testing the CATCHER最长下降子序列

#include "iostream"

using namespace std;

int a[32769],f[32769];

int main()

{

int i,j,n,max;

int count=0;

while(1)

{ count++;

scanf("%d",&a[0]);

if(a[0]==-1) break;

i=1;

while(1)

{

scanf("%d",&a[i]);

if(a[i]==-1)

break;

i++;

}

n=i;

max=0;

memset(f,0,sizeof(f));

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

{ f[i]=1;

for(j=0;j<=i;j++)

{

if(a[j-1]>a[i-1]&&f[j]+1>f[i])

f[i]=f[j]+1;

if(f[i]>max)

max=f[i];

}

}

printf("Test #%d:\n",count);

printf(" maximum possible interceptions: %d\n\n",max);

}

}

10:Pku acm 2533 Longest Ordered Subsequence最长上升子序列

#include "iostream"

using namespace std;

int f[10000];

int a[10000];

int main()

{

int n,i,j,max;

while(scanf("%d",&n)!=EOF)

{

for(i=0;i

{

scanf("%d",&a[i]);

}

memset(f,0,sizeof(f));

max=0;

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

{

f[i]=1;

for(j=0;j<=i;j++)

if(a[j-1]f[i])

f[i]=f[j]+1;

if(f[i]>max)

max=f[i];

}

printf("%d\n",max);

}

}

11:Pku acm 1631 Bridging signals最长上升子序列的加强版….二分法

#include "iostream"

#include "string"

using namespace std;

#define N 50000

int f[N];

int a[N];

int main()

{

int n,m,i,j,max;

scanf("%d",&n);

while(n--)

{

max=-99;

memset(f,0,sizeof(f));

scanf("%d",&m);

for(i=0;i

{

scanf("%d",&a[i]);

// f[i]=a[i];

}

f[1]=a[0];

int s=1;

int l,r,mid;

for(i=1;i

{

动态规划例题

例1:机器负荷分配问题 某公司新购进1000台机床,每台机床都可在高、低两种不同的负荷下进行生产,设在高负荷下生产的产量函数为g(x )=10x (单位:百件),其中x 为投入生产的机床数量,年完好率为a =0.7;在低负荷下生产的产量函数为h(y)=6y (单位:百件),其中y 为投人生产的机床数量,年完好率为b=0.9。计划连续使用5年,试问每年如何安排机床在高、低负荷下的生产计划,使在五年内生产的产品总产量达到最高。 例2:某企业通过市场调查,估计今后四个时期市场对某种产品的需要量如下表: 时期(k) 1 2 3 4 需要量(d k ) 2(单位) 3 2 4 假定不论在任何时期,生产每批产品的固定成本费为3(千元),若不生产,则为零;生产单位产品成本费为1(千元);每个时期生产能力所允许的最大生产批量为不超过6个单位,则任何时期生产x 个单位产品的成本费用为: 若 0<x ≤6 , 则生产总成本=3十1·x 若 x =0 , 则生产总成本=0 又设每个时期末未销售出去的产品,在一个时期内单位产品的库存费用为0.5(千元),同时还假定第1时期开始之初和在第4个时期之末,均无产品库存。现在我们的问题是;在满足上述给定的条件下,该厂如何安排各个时期的生产与库存,使所花的总成本费用最低? 例3:设某企业在第一年初购买一台新设备,该设备在五年内的年运行收益、年运行费用及更换新设备的净费用如下表:(单位:万元) 年份(k) 役龄(t) 运行收益()k g t 运行费用()k r t 更新费用()k c t 第一年 0 22 6 18 第二年 0 1 23 21 6 8 19 22

经典算法——动态规划教程

动态规划是对最优化问题的一种新的算法设计方法。由于各种问题的性质不同,确定最优解的条件也互不相同,因而动态规划的没计法对不同的问题,有各具特色的表示方式。不存在一种万能的动态规划算法。但是可以通过对若干有代表性的问题的动态规划算法进行讨论,学会这一设计方法。 多阶段决策过程最优化问题 ——动态规划的基本模型 在现实生活中,有一类活动的过程,由于它的特殊性,可将过程分成若干个互相联系的阶段,在它的每一阶段都需要作出决策,从而使整个过程达到最好的活动效果。因此各个阶段决策的选取不能任意确定,它依赖于当前面临的状态,又影响以后的发展。当各个阶段决策确定后,就组成一个决策序列,因而也就确定了整个过程的一条活动路线。这种把一个问题看做是一个前后关联具有链状结构的多阶段过程就称为多阶段决策过程,这种问题称为多阶段决策最优化问题。 【例题1】最短路径问题。图中给出了一个地图,地图中每个顶点代表一个城市,两个城市间的连线代表道路,连线上的数值代表道路的长度。现在,想从城市A到达城市E,怎样走路程最短,最短路程的长度是多少? 【分析】把从A到E的全过程分成四个阶段,用k表示阶段变量,第1阶段有一个初始状态A,两条可供选择的支路ABl、AB2;第2阶段有两个初始状态B1、 B2,B1有三条可供选择的支路,B2有两条可供选择的支路……。用dk(x k,x k+1)表示在第k阶段由初始状态x k到下阶段的初始状态x k+1的路径距离,Fk(x k)表示从第k阶段的x k到终点E的最短距离,利用倒推方法求解A到E的最短距离。具体计算过程如下: S1:K=4,有:F4(D1)=3,F4(D2)=4,F4(D3)=3 S2: K=3,有: F3(C1)=min{d3(C1,D1)+F4(D1),d3(C1,D2)+F4(d2)}=min{8,10}=8 F3(C2)=d3(C2,D1)+f4(D1)=5+3=8 F3(C3)=d3(C3,D3)+f4(D3)=8+3=11 F3(C4)=d3(C4,D3)+f4(D3)=3+3=6

动态规划讲解大全(含例题及答案)

动态规划讲解大全 动态规划(dynamic programming)是运筹学的一个分支,是求解决策过程(decision process)最优化的数学方法。20世纪50年代初美国数学家R.E.Bellman等人在研究多阶段决策过程(multistep decision process)的优化问题时,提出了著名的最优化原理(principle of optimality),把多阶段过程转化为一系列单阶段问题,逐个求解,创立了解决这类过程优化问题的新方法——动态规划。1957年出版了他的名著Dynamic Programming,这是该领域的第一本著作。 动态规划问世以来,在经济管理、生产调度、工程技术和最优控制等方面得到了广泛的应用。例如最短路线、库存管理、资源分配、设备更新、排序、装载等问题,用动态规划方法比用其它方法求解更为方便。 虽然动态规划主要用于求解以时间划分阶段的动态过程的优化问题,但是一些与时间无关的静态规划(如线性规划、非线性规划),只要人为地引进时间因素,把它视为多阶段决策过程,也可以用动态规划方法方便地求解。 动态规划程序设计是对解最优化问题的一种途径、一种方法,而不是一种特殊算法。不象前面所述的那些搜索或数值计算那样,具有一个标准的数学表达式和明确清晰的解题方法。动态规划程序设计往往是针对一种最优化问题,由于各种问题的性质不同,确定最优解的条件也互不相同,因而动态规划的设计方法对不同的问题,有各具特色的解题方法,而不存在一种万能的动态规划算法,可以解决各类最优化问题。因此读者在学习时,除了要对基本概念和方法正确理解外,必须具体问题具体分析处理,以丰富的想象力去建立模型,用创造性的技巧去求解。我们也可以通过对若干有代表性的问题的动态规划算法进行分析、讨论,逐渐学会并掌握这一设计方法。 基本模型 多阶段决策过程的最优化问题。 在现实生活中,有一类活动的过程,由于它的特殊性,可将过程分成若干个互相联系的阶段,在它的每一阶段都需要作出决策,从而使整个过程达到最好的活动效果。当然,各个阶段决策的选取不是任意确定的,它依赖于当前面临的状态,又影响以后的发展,当各个阶段决策确定后,就组成一个决策序列,因而也就确定了整个过程的一条活动路线,如图所示:(看词条图) 这种把一个问题看作是一个前后关联具有链状结构的多阶段过程就称为多阶段决策过程,这种问题就称为多阶段决策问题。 记忆化搜索 给你一个数字三角形, 形式如下: 1 2 3 4 5 6 7 8 9 10 找出从第一层到最后一层的一条路,使得所经过的权值之和最小或者最大. 无论对与新手还是老手,这都是再熟悉不过的题了,很容易地,我们写出状态转移方程:f(i, j)=a[i, j] + min{f(i+1, j),f(i+1, j + 1)} 对于动态规划算法解决这个问题,我们根据状态转移方程和状态转移方向,比较容易地写出动态规划的循环表示方法。但是,当状态和转移非常复杂的时候,也许写出循环式的动态规划就不是那么

动态规划习题答案

2.某公司有资金4百万元向A,B和C3个项目追加投资,各个项目可以有不同的投资额(百万元计),相应的效益如表所示。问怎样分配 资金,使总效益值最大?## 表8-47 解:设S-A,B,C项目的总投资额,S-B、C项目的总投资额21S-C 项目的投资额;3X-k项目的投资额;k(X-A项目的投资额,X -B项目的投资额,X-C项目的投资额)312W(S,X)-对K项目投资X后的收益:W(S,X)=W (X) kkkkkkkkk T (S,X)-S=S-X k k+1kkkk f (S)-当K至第3项目允许的投资额为S时所能获得的最大收益。kkk为获得最大利润,必须将4百万全部投资,假设有4阶段存在,有S=0,建立递归方程4f(S)=0 k4

f (S)=max{ W (X)+f(S)} k=3,2,1 k+1kk +1kkk X∈D(S) kkk第一步,K=3 f(S)=0 44 f (S)=max{W (X)+f (S)} 434333X∈D(S) 333S=S-X3 34 第二步:)} f (S (X (S)=max{W)+f K=2 322322) X ∈D(S 222-X =S S232 W (X)+f (S-X) 22322

第三步:)} (S (X) =max f (S {W)+ f K=1 211121) D X∈(S111- X S= S 1 21 ) (X- X)+ f (SW1 12 11 S=4 →S=1 →S=1 312↓↓ ↓ X*=3 X*=0 X*=1 312百万。1投资C 不投资B 百万,3投资A. 总收益164百万元。 3.(最优分配问题)有一个仪表公司打算向它的3个营业区设立6家销售店。每个营业区至少设一家,所获利润如表。问设立的6家销售店数应如何分配,可使总利润最大?

动态规划练习试题和解答

动态规划练习题 [题1] 多米诺骨牌(DOMINO) 问题描述:有一种多米诺骨牌是平面的,其正面被分成上下两部分,每一部分的表面或者为空,或者被标上1至6个点。现有一行排列在桌面上:顶行骨牌的点数之和为6+1+1+1=9;底行骨牌点数之和为1+5+3+2=11。顶行和底行的差值是2。这个差值是两行点数之和的差的绝对值。每个多米诺骨牌都可以上下倒置转换,即上部变为下部,下部变为上部。 现在的任务是,以最少的翻转次数,使得顶行和底行之间的差值最小。对于上面这个例子,我们只需翻转最后一个骨牌,就可以使得顶行和底行的差值为0,所以例子的答案为1。 输入格式: 文件的第一行是一个整数n(1〈=n〈=1000〉,表示有n个多米诺骨牌在桌面上排成一行。接下来共有n行,每行包含两个整数a、b(0〈=a、b〈=6,中间用空格分开〉。第I+1行的a、b分别表示第I个多米诺骨牌的上部与下部的点数(0表示空)。 输出格式: 只有一个整数在文件的第一行。这个整数表示翻动骨牌的最少次数,从而使得顶行和底行的差值最小。 [题2] Perform巡回演出 题目描述: Flute市的Phlharmoniker乐团2000年准备到Harp市做一次大型演出,本着普及古典音乐的目的,乐团指挥L.Y.M准备在到达Harp市之前先在周围一些小城市作一段时间的巡回演出,此后的几天里,音乐家们将每天搭乘一个航班从一个城市飞到另一个城市,最后才到达目的地Harp市(乐团可多次在同一城市演出). 由于航线的费用和班次每天都在变,城市和城市之间都有一份循环的航班表,每一时间,每一方向,航班表循环的周期都可能不同.现要求寻找一张花费费用最小的演出表. 输入: 输入文件包括若干个场景.每个场景的描述由一对整数n(2<=n<=10)和k(1<=k<=1000)开始,音乐家们要在这n个城市作巡回演出,城市用1..n标号,其中1是起点Flute市,n是终点Harp市,接下来有n*(n-1)份航班表,一份航班表一行,描述每对城市之间的航线和价格,第一组n-1份航班表对应从城市1到其他城市(2,3,...n)的航班,接下的n-1行是从城市2到其他城市(1,3,4...n)的航班,如此下去. 每份航班又一个整数d(1<=d<=30)开始,表示航班表循环的周期,接下来的d个非负整数表示1,2...d天对应的两个城市的航班的价格,价格为零表示那天两个城市之间没有航班.例如"3 75 0 80"表示第一天机票价格是75KOI,第二天没有航班,第三天的机票是80KOI,然后循环:第四天又是75KOI,第五天没有航班,如此循环.输入文件由n=k=0的场景结束. 输出: 对每个场景如果乐团可能从城市1出发,每天都要飞往另一个城市,最后(经过k天)抵达城市n,则输出这k个航班价格之和的最小值.如果不可能存在这样的巡回演出路线,输出0. 样例输入: 样例输出:

动态规划经典教程

动态规划经典教程 引言:本人在做过一些题目后对DP有些感想,就写了这个总结: 第一节动态规划基本概念 一,动态规划三要素:阶段,状态,决策。 他们的概念到处都是,我就不多说了,我只说说我对他们的理解: 如果把动态规划的求解过程看成一个工厂的生产线,阶段就是生产某个商品的不同的环节,状态就是工件当前的形态,决策就是对工件的操作。显然不同阶段是对产品的一个前面各个状态的小结,有一个个的小结构成了最终的整个生产线。每个状态间又有关联(下一个状态是由上一个状态做了某个决策后产生的)。 下面举个例子: 要生产一批雪糕,在这个过程中要分好多环节:购买牛奶,对牛奶提纯处理,放入工厂加工,加工后的商品要包装,包装后就去销售……,这样没个环节就可以看做是一个阶段;产品在不同的时候有不同的状态,刚开始时只是白白的牛奶,进入生产后做成了各种造型,从冷冻库拿出来后就变成雪糕(由液态变成固态=_=||)。每个形态就是一个状态,那从液态变成固态经过了冰冻这一操作,这个操作就是一个决策。 一个状态经过一个决策变成了另外一个状态,这个过程就是状态转移,用来描述状态转移的方程就是状态转移方程。 经过这个例子相信大家对动态规划有所了解了吧。 下面在说说我对动态规划的另外一个理解: 用图论知识理解动态规划:把动态规划中的状态抽象成一个点,在有直接关联的状态间连一条有向边,状态转移的代价就是边上的权。这样就形成了一个有向无环图AOE网(为什么无环呢?往下看)。对这个图进行拓扑排序,删除一个边后同时出现入度为0的状态在同一阶段。这样对图求最优路径就是动态规划问题的求解。 二,动态规划的适用范围 动态规划用于解决多阶段决策最优化问题,但是不是所有的最优化问题都可以用动态规划解答呢? 一般在题目中出现求最优解的问题就要考虑动态规划了,但是否可以用还要满足两个条件: 最优子结构(最优化原理) 无后效性 最优化原理在下面的最短路径问题中有详细的解答; 什么是无后效性呢? 就是说在状态i求解时用到状态j而状态j就解有用到状态k…..状态N。 而求状态N时有用到了状态i这样求解状态的过程形成了环就没法用动态规划解答了,这也是上面用图论理解动态规划中形成的图无环的原因。 也就是说当前状态是前面状态的完美总结,现在与过去无关。。。 当然,有是换一个划分状态或阶段的方法就满足无后效性了,这样的问题仍然可以用动态规划解。 三,动态规划解决问题的一般思路。 拿到多阶段决策最优化问题后,第一步要判断这个问题是否可以用动态规划解决,如果不能就要考虑搜索或贪心了。当却定问题可以用动态规划后,就要用下面介绍的方法解决问题了:(1)模型匹配法: 最先考虑的就是这个方法了。挖掘问题的本质,如果发现问题是自己熟悉的某个基本的模型,就直接套用,但要小心其中的一些小的变动,现在考题办都是基本模型的变形套用时要小心条件,三思而后行。这些基本模型在先面的分类中将一一介绍。 (2)三要素法 仔细分析问题尝试着确定动态规划的三要素,不同问题的却定方向不同: 先确定阶段的问题:数塔问题,和走路问题(详见解题报告) 先确定状态的问题:大多数都是先确定状态的。 先确定决策的问题:背包问题。(详见解题报告) 一般都是先从比较明显的地方入手,至于怎么知道哪个明显就是经验问题了,多做题就会发现。 (3)寻找规律法: 这个方法很简单,耐心推几组数据后,看他们的规律,总结规律间的共性,有点贪心的意思。 (4)边界条件法 找到问题的边界条件,然后考虑边界条件与它的领接状态之间的关系。这个方法也很起效。 (5)放宽约束和增加约束 这个思想是在陈启锋的论文里看到的,具体内容就是给问题增加一些条件或删除一些条件使问题变的清晰。 第二节动态规划分类讨论

动态规划习题

第七章动态规划 规划问题的最终目的就是确定各决策变量的取值,以使目标函数达到极大或极小。在线性规划和非线性规划中,决策变量都是以集合的形式被一次性处理的;然而,有时我们也会面对决策变量需分期、分批处理的多阶段决策问题。所谓多阶段决策问题是指这样一类活动过程:它可以分解为若干个互相联系的阶段,在每一阶段分别对应着一组可供选取的决策集合;即构成过程的每个阶段都需要进行一次决策的决策问题。将各个阶段的决策综合起来构成一个决策序列,称为一个策略。显然,由于各个阶段选取的决策不同,对应整个过程可以有一系列不同的策略。当过程采取某个具体策略时,相应可以得到一个确定的效果,采取不同的策略,就会得到不同的效果。多阶段的决策问题,就是要在所有可能采取的策略中选取一个最优的策略,以便得到最佳的效果。动态规划(dynamic programming)同前面介绍过的各种优化方法不同,它不是一种算法,而是考察问题的一种途径。动态规划是一种求解多阶段决策问题的系统技术,可以说它横跨整个规划领域(线性规划和非线性规划)。当然,由于动态规划不是一种特定的算法,因而它不象线性规划那样有一个标准的数学表达式和明确定义的一组规则,动态规划必须对具体问题进行具体的分析处理。在多阶段决策问题中,有些问题对阶段的划分具有明显的时序性,动态规划的“动态”二字也由此而得名。动态规划的主要创始人是美国数学家贝尔曼(Bellman)。20世纪40年代末50年代初,当时在兰德公司(Rand Corporation)从事研究工作的贝尔曼首先提出了动态规划的概念。1957年贝尔曼发表了数篇研究论文,并出版了他的第一部著作《动态规划》。该著作成为了当时唯一的进一步研究和应用动态规划的理论源泉。1961年贝尔曼出版了他的第二部著作,并于1962年同杜瑞佛思(Dreyfus)合作出版了第三部著作。在贝尔曼及其助手们致力于发展和推广这一技术的同时,其他一些学者也对动态规划的发展做出了重大的贡献,其中最值得一提的是爱尔思(Aris)和梅特顿(Mitten)。爱尔思先后于1961年和1964年出版了两部关于动态规划的著作,并于1964年同尼母霍思尔(Nemhauser)、威尔德(Wild)一道创建了处理分枝、循环性多阶段决策系统的一般性理论。梅特顿提出了许多对动态规划后来发展有着重要意义的基础性观点,并且对明晰动态规划路径的数学性质做出了巨大的贡献。 动态规划在工程技术、经济管理等社会各个领域都有着广泛的应用,并且获得了显著的效果。在经济管理方面,动态规划可以用来解决最优路径问题、资源分配问题、生产调度问题、库存管理问题、排序问题、设备更新问题以及生产过程最优控制问题等,是经济管理中一种重要的决策技术。许多规划问题用动态规划的方法来处理,常比线性规划或非线性规划更有效。特别是对于离散的问题,由于解析数学无法发挥作用,动态规划便成为了一种非常有用的工具。 动态规划可以按照决策过程的演变是否确定分为确定性动态规划和随机性动态规划;也可以按照决策变量的取值是否连续分为连续性动态规划和离散性动态规划。本教材主要介绍动态规划的基本概念、理论和方法,并通过典型的案例说明这些理论和方法的应用。 §7.1 动态规划的基本理论 1.1多阶段决策过程的数学描述 有这样一类活动过程,其整个过程可分为若干相互联系的阶段,每一阶段都要作出相应的决策,以使整个过程达到最佳的活动效果。任何一个阶段(stage,即决策点)都是由输入(input)、决策(decision)、状态转移律(transformation function)和输出(output)构成的,如图7-1(a)所示。其中输入和输出也称为状态(state),输入称为输入状态,输出称为输出状态。

动态规划习题精讲

信息学竞赛中的动态规划专题 哈尔滨工业大学周谷越 【关键字】 动态规划动机状态典型题目辅助方法优化方法 【摘要】 本文针对信息学竞赛(面向中学生的Noi以及面向大学生的ACM/ICPC)中的动态规划算法,从动机入手,讨论了动态规划的基本思想和常见应用方法。通过一些常见的经典题目来归纳动态规划的一般作法并从理论上加以分析和说明。并介绍了一些解决动态规划问题时的一些辅助技巧和优化方法。纵观全文可知,动态规划的关键在于把握本质思想的基础上灵活运用。 【目录】 1.动态规划的动机和基本思想 1.1.解决重复子问题 1.2.解决复杂贪心问题 2.动态规划状态的划分方法 2.1.一维状态划分 2.2.二维状态划分 2.3.树型状态划分 3.动态规划的辅助与优化方法 3.1.常见辅助方法 3.2.常见优化方法 4.近年来Noi动态规划题目分析 4.1 Noi2005瑰丽华尔兹 4.2 Noi2005聪聪与可可 4.3 Noi2006网络收费 4.4 Noi2006千年虫 附录参考书籍与相关材料

1.动态规划的动机和基本思想 首先声明,这里所说的动态规划的动机是从竞赛角度出发的动机。 1.1 解决重复子问题 对于很多问题,我们利用分治的思想,可以把大问题分解成若干小问题,然后再把各个小问题的答案组合起来,得到大问题的解答。这类问题的共同点是小问题和大问题的本质相同。很多分治法可以解决的问题(如quick_sort,hanoi_tower等)都是把大问题化成2个以内的不相重复的小问题,解决的问题数量即为∑(log2n / k)。而考虑下面这个问题: USACO 1.4.3 Number Triangles http://122.139.62.222/problem.php?id=1417 【题目描述】 考虑在下面被显示的数字金字塔。 写一个程序来计算从最高点开始在底部任意处结束的路径经过数字的和的最大。每一步可以走到左下方的点也可以到达右下方的点。 7 3 8 8 1 0 2 7 4 4 4 5 2 6 1 在上面的样例中,从7到3到8到7到5的路径产生了最大和:30。 【输入格式】 第一个行包含R(1<= R<=1000) ,表示行的数目。后面每行为这个数字金字塔特定行包含的整数。所有的被供应的整数是非负的且不大于100。 【输出格式】 单独的一行包含那个可能得到的最大的和。 【样例输入】 5 7 3 8 8 1 0 2 7 4 4 4 5 2 6 1 【样例输出】 30 显然,我们同样可以把大问题化成小问题来解决。如样例中最底层的6就可以从次底层

动态规划经典案例详解(背包问题)

动态规划经典案例详解之背包问题 【摘要】本文主要从动态规划经典案例——背包问题的动态规划设计思路出发,结合具体实例,对动态规划在程序设计中的典型应用以及衍生拓展进行详细分析。 【关键字】动态规划信息学奥赛0/1背包问题 动态规划并非一个算法,而是一种解题的思路,其核心思想是通过使用大量的存储空间把中间结果记录下来,大大减少重复计算的时间,从而提高的程序的执行效率,因为信息学奥林匹克复赛题目的解决程序一般是有时间限制的,对于某些用搜索必然耗费大量时间的题目,动态规划几乎是唯一的选择。但是动态规划并没有一个简单的模型可以套用,对于每个不同的题目都有对应的不同规划思路,我们只能通过对一些动态规划经典案例的学习来训练自己的动态规划思维能力,从而以不变应万变,应付各种复杂的程序设计,本文通过对动态规划经典案例之一的背包问题进行详细阐述,旨在让学生了解动态规划和搜索的不同设计思路以及动态规划的优越性。 【原型例题】 从n个物品中选取装入背包的物品,每件物品i的重量为wi,价值为pi。求使物品价值最高的选取方法。 【输入文件】 第一行一个数c,为背包容量。 第二行一个数n,为物品数量 第三行n个数,以空格间隔,为n个物品的重量 第四行n个数,以空格间隔,为n个物品的价值 【输出文件】 能取得的最大价值。 【分析】 初看这类问题,第一个想到的会是贪心,但是贪心法却无法保证一定能得到最优解,看以下实例: 贪心准则1:从剩余的物品中,选出可以装入背包的价值最大的物品,利用这种规则,价值最大的物品首先被装入(假设有足够容量),然后是下一个价值最大的物品,如此继续下去。这种策略不能保证得到最优解。例如,考虑n=2,w=[100,10,10],p=[20,15,15],c=105。当利用价值贪婪准则时,获得的解为x=[1,0,0],这种方案的总价值为20。而最优解为[0,1,1],其总价值为30。 贪心准则2:从剩下的物品中选择可装入背包的重量最小的物品。虽然这种规则对于前面的例子能产生最优解,但在一般情况下则不一定能得到最优解。考虑n=2,w=[10,20], p=[5,100],c=25。当利用重量贪婪策略时,获得的解为x=[1,0],比最优解[0,1]要差。

动态规划典型例题

1、单调递增最长子序列 描述 求一个字符串的最长递增子序列的长度 如:dabdbf最长递增子序列就是abdf,长度为4 输入 第一行一个整数0

2、最长公共子序列 描述 如题,需要写一个程序,得出最长公共子序列。 tip:最长公共子序列也称作最长公共子串(不要求连续),英文缩写为LCS(Longest Common Subsequence)。其定义是,一个序列S ,如果分别是两个或多个已知序列的子序列,且是所有符合此条件序列中最长的,则S 称为已知序列的最长公共子序列。 输入 第一行给出一个整数N(0

3、括号匹配 时间限制:1000 ms | 内存限制:65535 KB 描述 给你一个字符串,里面只包含"(",")","[","]"四种符号,请问你需要至少添加多少个括号才能使这些括号匹配起来。 如: []是匹配的 ([])[]是匹配的 ((]是不匹配的 ([)]是不匹配的 输入 第一行输入一个正整数N,表示测试数据组数(N<=10) 每组测试数据都只有一行,是一个字符串S,S中只包含以上所说的四种字符, S的长度不超过100 输出 对于每组测试数据都输出一个正整数,表示最少需要添加的括号的数量。每组 测试输出占一行 样例输入 4 [] ([])[] ((] ([)] 样例输出 3 2

动态规划习题完整版

动态规划习题 Document serial number【NL89WT-NY98YT-NC8CB-NNUUT-NUT108】

动态规划专题分类视图数轴动规题: 题1.2001年普及组第4题--装箱问题 【问题描述】有一个箱子容量为V(正整数,0≤V≤20000),同时有n个物品(0

对于100%的数据,砝码的种类n满足:1≤n≤100; 对于30%的数据,砝码的总数量C满足:1≤C≤20; 对于100%的数据,砝码的总数量C满足:1≤C≤100; 对于所有的数据,砝码的总重量W满足:1≤W≤400000; 题3.石子归并-szgb.pas 【问题描述】有一堆石头质量分别为W1,W2,…,Wn.(Wi≤10000),将石头合并为两堆,使两堆质量的差最小。 【输入】输入文件szgb.in的第一行只有一个整数n(1≤n≤50),表示有n堆石子。接下去的n行,为每堆石子质量。 【输出】输出文件szgb.out的只有一行,该行只有一个整数,表示最小的质量差. 【样例输入】 5 5 8 13 27 14 【样例输出】 3 题4.补圣衣 【问题描述】有四个人,每人身上的衣服分别有s1,s2,s3和s4处破损,而且每处破损程度不同,破损程度用需修好它用的时间表示 (A1...As1,B1...Bs2,C1...Cs3,D1...Ds4)。不过你可以同时修补2处破损。但是这2处破损,只能是同一件衣服上的。就是说你只能同时修补一件衣服,修好了,才能修补下一件。 【输入】本题包含5行数据:第1行,为s1,s2,s3,s4(1≤s1,s2,s3,s4≤20) 第2行,为A1...As1共s1个数,表示第一件衣服上每个破损修好它所需的时间 第3行,为B1...Bs2共s2个数,表示第二件衣服上每个破损修好它所需的时间 第4行,为C1...Cs3共s3个数,表示第三件衣服上每个破损修好它所需的时间 第5行,为D1...Ds4共s4个数,表示第四件衣服上每个破损修好它所需的时间 (1≤A1...As1,B1...Bs2,C1...Cs3,D1...Ds4≤60) 【输出】输出一行,为修好四件衣服所要的最短时间。 【样例输入】 1213 5 43 6 243 【样例输出】 20 题5.光光的作业homework.pas/homework.exe 【问题描述】光光上了高中,科目增多了。在长假里,光光的老师们都非常严厉,都给他布置了一定量的作业。假期里,光光一共有的时间是k小时。在长假前,老师们一共给光光布置了n份作业,第i份作业需要的时间是ti小时。但是由于老师们互相不

动态规划入门(论文)

动态规划思想入门 作者:陈喻(2008年10月7日)关键字:动态规划,最优子结构,记忆化搜索 引言 动态规划(dynamic programming)是运筹学的一个分支,是求解决策过程(decisionprocess)最优化的数学方法。20世纪50年代初美国数学家R.E.Bellman等人在研究多阶段决策过程(multistep decision process)的优化问题时,提出了著名的最优化原理(principle of optimality),把多阶段过程转化为一系列单阶段问题,逐个求解,创立了解决这类过程优化问题的新方法——动态规划。1957年出版了他的名著Dynamic Programming,这是该领域的第一本著作。 动态规划问世以来,在经济管理、生产调度、工程技术和最优控制等方面得到了广泛的应用。例如最短路线、库存管理、资源分配、设备更新、排序、装载等问题,用动态规划方法比用其它方法求解更为方便。 虽然动态规划主要用于求解以时间划分阶段的动态过程的优化问题,但是一些与时间无关的静态规划(如线性规划、非线性规划),只要人为地引进时间因素,把它视为多阶段决策过程,也可以用动态规划方法方便地求解。 动态规划的基本思想 动态规划是:将待求的问题分解成若干个相互联系的子问题,先求解子问题,然后从这些子问题的解得到原问题的解;对于重复出现的子问题,只在第一次遇到的时候对它直接求解,并把答案保存起来,让以后再次遇到是直接引用答案,不必从新求解,其实质是分治思想和解决冗余。

例1:求A—>B的最短路径 图1 这是一个利用动态规划思想的经典问题,通过直接观察图1我们可以枚举出20多条路径,并可以计算出其中最短的路径长度为16

经典的动态规划入门练习题

动态规划入门练习题 1.石子合并 在一个圆形操场的四周摆放着N堆石子(N<= 100),现要将石子有次序地合并成一堆.规定每次只能选取相邻的两堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分.编一程序,由文件读入堆栈数N及每堆栈的石子数(<=20). (1)选择一种合并石子的方案,使用权得做N-1次合并,得分的总和最小; (2)选择一种合并石子的方案,使用权得做N-1次合并,得分的总和最大; 输入数据: 第一行为石子堆数N; 第二行为每堆的石子数,每两个数之间用一个空格分隔. 输出数据: 从第一至第N行为得分最小的合并方案.第N+1行是空行.从第N+2行到第2N+1行是得分最大合并方案.每种合并方案用N行表示,其中第i行(1<=i<=N)表示第i次合并前各堆的石子数(依顺时针次序输出,哪一堆先输出均可).要求将待合并的两堆石子数以相应的负数表示. 输入输出范例: 输入: 4 4 5 9 4 输出: -459-4 -8-59 -13-9 224-5-94 4-14-4 -4-18 22 最小代价子母树设有一排数,共n个,例如:22 14 7 13 26 15 11.任意2个相邻的数可以进行归并,归并的代价为该两个数的和,经过不断的归并,最后归为一堆,而全部归并代价的和称为总代价,给出一种归并算法,使总代价为最小. 输入、输出数据格式与“石子合并”相同。 输入样例: 4 12 5 16 4 输出样例: -12-5164 17-16-4 -17-20 37

2.背包问题 设有n种物品,每种物品有一个重量及一个价值。但每种物品的数量是无限的,同时有一个背包,最大载重量为XK,今从n种物品中选取若干件(同一种物品可以多次选取),使其重量的和小于等于XK,而价值的和为最大。 输入数据: 第一行两个数:物品总数N,背包载重量XK;两个数用空格分隔; 第二行N个数,为N种物品重量;两个数用空格分隔; 第三行N个数,为N种物品价值; 两个数用空格分隔; 输出数据: 第一行总价值; 以下N行,每行两个数,分别为选取物品的编号及数量; 输入样例: 4 10 2 3 4 7 1 3 5 9 输出样例: 12 2 1 4 1 3.商店购物 某商店中每种商品都有一个价格。例如,一朵花的价格是2 ICU(ICU 是信息学竞赛的货币的单位);一个花瓶的价格是5 ICU。为了吸引更多的顾客,商店提供了特殊优惠价。特殊优惠商品是把一种或几种商品分成一组。并降价销售。例如:3朵花的价格不是6而是5 ICU ;2个花瓶加1朵花是10 ICU不是12 ICU。 编一个程序,计算某个顾客所购商品应付的费用。要充分利用优惠价以使顾客付款最小。请注意,你不能变更顾客所购商品的种类及数量,即使增加某些商品会使付款总数减小也不允许你作出任何变更。假定各种商品价格用优惠价如上所述,并且某顾客购买物品为:3朵花和2个花瓶。那么顾客应付款为14 ICU 因为: 1朵花加2个花瓶: 优惠价:10 ICU 2朵花正常价: 4 ICU 输入数据 用两个文件表示输入数据。第一个文件INPUT.TXT描述顾客所购物品(放在购物筐中);第二个文件描述商店提供的优惠商品及价格(文件名为OFF ER.TXT)。两个文件中都只用整数。 第一个文件INPUT.TXT的格式为:第一行是一个数字B(0≤B≤5),表示所购商品种类数。下面共B行,每行中含3个数C,K,P。 C 代表商品的编码(每种商品有一个唯一的编码),1≤C≤999。K代表该种商品购买总数,1≤K≤5。P 是该种商品的正常单价(每件商品的价格),1≤P≤999。请注意,购物筐中最多可放5*5=25件商品。 第二个文件OFFER.TXT的格式为:第一行是一个数字S(0≤S≤9 9),表示共有S 种优惠。下面共S行,每一行描述一种优惠商品的组合中商品的种类。下面接着是几个数字对(C,K),其中C代表商品编码,1≤C≤9 99。K代表该种商品在此组合中的数量,1≤K≤5。本行最后一个数字P(1≤ P≤9999)代表此商品组合的优惠价。当然,优惠价要低于该组合中商品正常价之总和。 输出数据 在输出文件OUTPUT.TXT中写一个数字(占一行),该数字表示顾客所购商品(输入文件指明所购商品)

动态规划练习题合集(Dp-合集)

一、关键子工程(project.c/cpp/pas) 在大型工程的施工前,我们把整个工程划分为若干个子工程,并把这些子工程编号为1、2、……、N;这样划分之后,子工程之间就会有一些依赖关系,即一些子工程必须在某些子工程完成之后才能施工。由于子工程之间有相互依赖关系,因此有两个任务需要我们去完成:首先,我们需要计算整个工程最少的完成时间;同时,由于一些不可预测的客观因素会使某些子工程延期,因此我们必须知道哪些子工程的延期会影响整个工程的延期,我们把有这种特征的子工程称为关键子工程,因此第二个任务就是找出所有的关键子工程,以便集中精力管理好这些子工程,尽量避免这些子工程延期,达到用最快的速度完成整个工程。为了便于编程,现在我们假设: (1)根据预算,每一个子工程都有一个完成时间。 (2)子工程之间的依赖关系是:部分子工程必须在一些子工程完成之后才开工。 (3)只要满足子工程间的依赖关系,在任何时刻可以有任何多个子工程同时在施工,也既同时施工的子工程个数不受限制。 (4)整个工程的完成是指:所有子工程的完成。 其中,表格中第I+1行J+2列的值如为0表示“子工程I”可以在“子工程J”没完成前施工,为1表示“子工程I”必须在“子工程J”完成后才能施工。上述工程最快完成时间为14天,其中子工程1、3、4、5为关键子工程。 又例如,有五个子工程的工程规划表: 上述的子工程划分不合理,因为无法安排子工程1,3,4的施工。 输入数据: 第1行为N,N是子工程的总个数,N≤200。 第2行为N个正整数,分别代表子工程1、2、……、N的完成时间。 第3行到N+2行,每行有N-1个0或1。其中的第I+2行的这些0,1,分别表示“子工程I”与子工程1、2、…、I-1、I+1、…N的依赖关系,(I=1、2、……、N)。每行数据之间均用一个空格分开。 输出数据:

动态规划理论(精华)

动态规划理论 一.动态规划的逆向思维法 动态规划是一种思维方法,没有统一的、具体的模式。动态规划可以从多方面去考察,不同的方面对动 态规划有不同的表述。我们不打算强加一种统一的表述,而是从多个角度对动态规划的思维方法进行讨 论,希望大家在思维具体问题时,也能够从多个角度展开,这样收获会更大。 逆向思维法是指从问题目标状态出发倒推回初始状态或边界状态的思维方法。如果原问题可以分解成 几个本质相同、规模较小的问题,很自然就会联想到从逆向思维的角度寻求问题的解决。 你也许会想,这种将大问题分解成小问题的思维不就是分治法吗?动态规划是不是分而治之呢?其实, 虽然我们在运用动态规划的逆向思维法和分治法分析问题时,都使用了这种将问题实例归纳为更小的、 相似的子问题,并通过求解子问题产生一个全局最优值的思路,但动态规划不是分治法:关键在于分解 出来的各个子问题的性质不同。 分治法要求各个子问题是独立的(即不包含公共的子问题),因此一旦递归地求出各个子问题的解后, 便可自下而上地将子问题的解合并成原问题的解。如果各子问题是不独立的,那么分治法就要做许多不 必要的工作,重复地解公共的子问题。 动态规划与分治法的不同之处在于动态规划允许这些子问题不独立(即各子问题可包含公共的子问题) ,它对每个子问题只解一次,并将结果保存起来,避免每次碰到时都要重复计算。这就是动态规划高效

的一个原因。 动态规划的逆向思维法的要点可归纳为以下三个步骤: (1)分析最优值的结构,刻画其结构特征; (2)递归地定义最优值;0 (3)按自底向上或自顶向下记忆化的方式计算最优值。 【例题1】背包问题描述: 有一个负重能力为m的背包和n种物品,第i种物品的价值为v,重量为w。在不超过背包负重能力的前 提下选择若干个物品装入背包,使这些的物品的价值之和最大。每种物品可以不选,也可以选择多个。 假设每种物品都有足够的数量。 分析: 从算法的角度看,解决背包问题一种最简单的方法是枚举所有可能的物品的组合方案并计算这个组合 方案的价值之和,从中找出价值之和最大的方案。显然,这种靠穷举所有可能方案的方法不是一种有效 的算法。 但是这个问题可以使用动态规划加以解决。下面我们用动态规划的逆向思维法来分析这个问题。 (1)背包问题最优值的结构 动态规划的逆向思维法的第一步是刻画一个最优值的结构,如果我们能分析出一个问题的最优值包含 其子问题的最优值,问题的这种性质称为最优子结构。一个问题的最优子结构性质是该问题可以使用动 态规划的显著特征。 对一个负重能力为m的背包,如果我们选择装入一个第 i 种物品,那么原背包问题就转化为负重能力 为 m-w 的子背包问题。原背包问题的最优值包含这个子背包问题的最优值。若我们用背包的负重能力来 划分状态,令状态变量s[k]表示负重能力为k的背包,那么s[m]的值只取决于s[k](k≤m)的值。因此背包

动态规划例1求解下列整数规划的最优解

例1 求解下列整数规划的最优解: ()123 123max 45634510..01,2,3,j j Z x x x x x x s t x j x =++++???=??≤≥为整数. 解 (1)建立动态规划模型: 阶段变量:将给每一个变量j x 赋值看成一个阶段,划分为3个阶段,且阶段变量k=1,2,3. 设状态变量k s 表示从第k 阶段到第3阶段约束右端最大值,则10.j s = 设决策变量k x 表示第k 阶段赋给变量k x 的值(1,2,3)k =. 状态转移方程:2113223,4.s s x s s x =-=- 阶段指标:111122223333(,)4,(,)5,(,)6.u s x x u s x x u s x x === 基本方程; ()(){}()3113,2,1044 ()max ,()0.s k k k k k k k k k k x a f s u s x f s f s ++??=????? ??=+???=?≤≤ 其中1233,4, 5.a a a === (1) 用逆序法求解: 当3k =时, ()(){}{}33333443330055max 6max 6,s s x x f s x f s x ???? ?? ?? ?????? ?? =+=≤≤≤ 而{}[]30,1,2,3,4,5,6,7,8,9,10.s x ∈表示不超过x 的最大整数。因此,当30,1,2,3,4s =时, 30x =;当35,6,7,8,9s =时,3x 可取0或1;当310s =时,3x 可取0,1,2,由此确定()33. f s 现将有关数据列入表中 表中.

几个经典的动态规划问题

动态规划复习: 《便宜的旅行》分析: 这个问题很明显是一个动态规划的标准问题。 考虑某一天晚上车队到达了终点,上一次的花销必然是只与早上车队所在的位置有关的。这样,由于要求从起点到终点最优的方案,所以从起点到达早上所出发时旅馆的方案也应该是最优的。以此类推,我们可以得出我们应该求出从起点到各个旅馆的最优方案。这样,如果我们设从起点到旅馆s i∈S (1≤ i≤ n)的最优方案的价值为f(s i),就可以得到如下的动态规划方程: F(s[i])=min{f(s[j])}+value[i]; 0<=s[i]-s[j]<=800 这里value(s i)为s i的价值。 《蛙人》 设F(i,j) 是携带i升氧气,j升氮气的最小重量 F(i+a k,j+t k)=min{f(i,j)+W k}

李曙华同学程序 for i:=0 to 21 do for j:=0 to 79 do a[i,j]:=10000000; a[0,0]:=0; for i:=1 to n do begin readln(b[i,1],b[i,2],b[i,3]); for j:=21-b[i,1] downto 0 do for k:=79-b[i,2] downto 0 do begin if a[j,k]>a[j,k+1] then a[j,k]:=a[j,k+1]; if a[j,k]>a[j+1,k] then a[j,k]:=a[j+1,k]; if a[j+b[i,1],k+b[i,2]]>a[j,k]+b[i,3] then a[j+b[i,1],k+b[i,2]]:=a[j,k]+b[i,3]; end; end; writeln(a[x,y]); close(input);close(output); end.

相关文档
最新文档