码迷,mamicode.com
首页 > 其他好文 > 详细

【读书笔记/解题报告/复健向】动态规划

时间:2015-06-26 19:25:24      阅读:139      评论:0      收藏:0      [点我收藏+]

标签:

《挑战程序设计竞赛》2.3.1(POJ3624/NOIP2004采药问题)

最基础的01背包问题,标程性质,又二维和一维两种写法。

技术分享
 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<cmath>
 5 using namespace std;
 6 const int MAXN=3403;
 7 int w[MAXN];
 8 int v[MAXN];
 9 int W;
10 int f[MAXN][MAXN];
11 
12 int main()
13 {
14     int n;
15     scanf("%d%d",&n,&W);
16     memset(f,0,sizeof(f));
17     for (int i=1;i<=n;i++) scanf("%d%d",&w[i],&v[i]);
18     for (int i=1;i<=n;i++)
19         for (int j=1;j<=W;j++)
20         {
21             f[i][j]=f[i-1][j];
22             if (j>=w[i]) f[i][j]=max(f[i][j],f[i-1][j-w[i]]+v[i]);
23         }
24     cout<<f[n][W]<<endl;
25 }
View Code(二维)
技术分享
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<cstring>
 5 using namespace std;
 6 const int MAXN=12890;
 7 int f[MAXN];
 8 
 9 int main()
10 {
11     int N,M;
12     scanf("%d%d",&N,&M);
13     memset(f,0,sizeof(f));
14     for (int i=0;i<N;i++)
15     {
16         int w,d;
17         scanf("%d%d",&w,&d);
18         for (int j=M;j>=w;j--)
19             if ((f[j-w]+d) > f[j]) f[j]=f[j-w]+d;
20     }
21     cout<<f[M]<<endl;
22     return 0;
23 }
View Code(一维)

解释一下笔者第一次学01背包时容易遇到的困扰:

?为什么一维中要从后往前?因为一维并没有限制取到哪一个背包,从后往前防止再累加过一遍当前物品的基础上再次累加。

?为什么二维中需要if (j<w[i]) f[i][j]=f[i-1][j]?这个语句而一维中不需要类似语句?因为没有限制当前取到哪一个背包,取前一个背包代价为j时的情况已经记录了下来。

?二维背包能从后往前做吗?可以,对f[i][j]产生影响的只有它自身和f[i-1]中数据,前后次序无关。

?为什么一维中输出的时候输出f[M]或F[n][M]即可?背包问题中F[n][M]并不代表恰好取前n个包,总价值恰好为M,而是在这个范围内的最大值。不理解的话想一想以下的情况:若第一个物品价值为1,f[1][2]=f[0][1]+1,但是此时取到的总价值只有1,第二个下标却为2。

?二维背包能由当前位置推向后面吗?可以,见下面给出的程序

技术分享
 1 int dp()
 2 {
 3     for (int i=0;i<n;i++)
 4     {
 5         for (int i=0;j<=W;j++ 6         {
 7                 f[i+1][j]=max(f[i+1,j],f[i][j]);
 8                 if (j+w[i]<=W) f[i+1][j+w[i]]=max(f[i+1][j+w[i]],f[i][j]+v[i]);
 9         }
10     }
11     cout<<f[n][W]<<endl;    \\因为往后递推,最终数据保存在了f[n]中
12 }
View Code(二维另版)

明白了上述三个问题,01背包就基本可以算是理解透彻了。《挑战程序设计竞赛》在2.3.1中有对记忆化搜索的阐述,也可以关注一下。

至此,最基本的01背包问题就讲解结束了。

 

《挑战程序设计竞赛》2.3.1最长公共子序列(POJ1458)

01背包问题问题的拓展应用。思路非常简单,如下:

f[i][j]表示s1取到第i位,s2取到第j位时的最长公共子序列长度。如果s1[i]≠s2[j]在,则f[i,j]=max(f[i-1,j],f[i,j-1]),否则再增加一个比较对象f[i-1][j-1]+1

虽然思路是秒杀的,但是POJ1458涉及到字符串的读取,麻烦死了,几乎每次碰到字符串我都要跪,参考了他人的程序,折腾了好长时间,不过总算一遍就AC了。程序里的细节解释后期来说明,到时候会做一个字符串读取和处理的专题

 

技术分享
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cmath>
 5 using namespace std;
 6 const int MAXN=1001;
 7 char s1[MAXN];
 8 char s2[MAXN];
 9 int f[MAXN][MAXN];
10 
11 int main()
12 {
13 
14     while (scanf("%s%s",s1+1,s2+1)!=EOF)
15     {
16         int len1=strlen(s1+1),len2=strlen(s2+1);
17         memset(f,0,sizeof(f));
18         for (int i=1;i<=len1;i++)
19             for (int j=1;j<=len2;j++)
20             {
21                 f[i][j]=max(f[i-1][j],f[i][j-1]);
22                 if (s1[i]==s2[j]) f[i][j]=f[i-1][j-1]+1;
23             }
24         cout<<f[len1][len2]<<endl;
25     }
26     return 0;
27 }
View Code

 

 

《挑战程序设计竞赛》2.3.2完全背包问题

完全背包问题和01背包问题的区别在于:每种物品可以挑选任意多件。完全背包问题和01背包问题一样,都有二维和一维的两种写法

TBC.

 

【读书笔记/解题报告/复健向】动态规划

标签:

原文地址:http://www.cnblogs.com/iiyiyi/p/4602851.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!