动态规划:分阶段求取最优解的问题,在一些简单的题中直接就是递归运算
动态规划每一个阶段都有与之相对应的状态,都面临着不同的抉择
特别是要想办法分成若干个子问题来进行分解寻找最优解。
所以现在要行办法获得递归关系式
first:
小明写了一个简单的吃金币游戏,规则如下:
在一个长方形地图上,玩家每次能从一个方格走到相邻一个方格。
玩家控制的角色可以向下或者向右走,但不能向上或向左走。
每个方格上都有一定的金币。
现在,小明想请你帮他想一个策略,尽可能多的获得金币
(从左上角走到右下角可能获得的最大金币数)。
解析:从第一步开始,每一步都有两种走法,一个是向下,一个是向右,但是最后一共走了m+n步,我们用倒推的思考,假设现在已经走到了i行,j列,上一步的走法无非有·两种,我们用倒推的方法寻找两个中的最大值
f[i][j]=(f[i][i-1],f[i-1][j])+coin
#include<bit/stdc++.h>
using namespace std;
const int maxn=105;
int main(){
int f[maxn][maxn],m,n,coin;
for(int i=0;i<=m;i++)
for(int j=0;j<=n;j++)
{
cin>>coin;//每个方格里输入金币的数目
f[i][j]=max(f[i][j-1],f[i-1][j]+coin;//从中选取最优解
)
}
cout<<f[m][n];
return 0;
}
一个数的序列bi,当b1 < b2 < … < bS 的时候,我们称这个序列是上升的。对于给定的一个序列(a1, a2, …, aN),我们可以得到一些上升的子序列(ai1, ai2, …, aiK),这里1 <= i1 < i2 < … <iK <= N。
比如,对于序列(1, 7, 3, 5, 9, 4, 8),有它的一些上升子序列,如(1, 7), (3, 4, 8)等等。这些子序列中最长的长度是4,比如子序列(1, 3, 5, 8).你的任务,就是对于给定的序列,求出最长上升子序列的长度。
输入数据
输入的第一行是序列的长度N (1 <= N <= 1000)。第二行给出序列中的N 个整数,这些整数的取值范围都在0 到10000。
输出要求
最长上升子序列的长度。
输入样例
7
1 7 3 5 9 4 8
输出样例
4
解析:
很明显这个就是有很多不同的状态,那遇到类似的题应该如何进行分配呢
“求以k(k=1, 2, 3…N)为终点的最长上升子序列的长度”是个好的子问题。子问题具有相同的求解方式通过求第N-1个上升子序列与N个子序列进行比较,挨个进行比较,求出每个N结尾时所有的所有上升子序列,但是代码的实现还是需要一些技巧
a[i]表示第i个元素
dp[i]表示以a[i]结尾的最大子段和
dp[i] = max{a[i], dp[i-1] + a[i]}
解释一下方程:
如果dp[i-1] > 0,则 dp[i] = dp[i-1] + a[i]
如果dp[i-1] < 0,则 dp[i] = a[i]
因为不用记录位置信息,所以dp[]可以用一个变量dp代替:
如果dp > 0,则dp += a[i]
如果dp < 0,则dp = a[i]
#include<bit/stdc++.h>
using namespace std;
const int maxn=1005
int b[maxn + 10];
int L[maxn + 10];//最长上升子序列的长度
int main()
{
int i, j, N;
cin>>n;
for( i = 1;i <= N;i ++ )
cin>>b[i]//输入了所有序列
L[1] = 1;
for( i = 2; i <= N; i ++ )
{
int L1 = 0; //记录第i 个数左边子序列最大长度
for( j = 1; j < i; j ++ )
{ //搜索以第i 个数左边数为终点的最长上升子序列长度
if( b[i] > b[j] ) //双重循环进行比较
{
if(L1 < L[j] )
L1 = L[j];
}
}
L[i] = L1 + 1;//这一步是对所有已经求出的每个N的子序列进行记录
}
int sum = -1;
for( i = 1;i <= N;i ++ )
if( sum < L[i])
sum = L[i];
cout<<sum<<endl;
return 0;
}
如何对其进行更新·:当后一个值大于前一个值时,记录当前值,但是如果后一个值小于这个值时,不进行记载,跳过完成更新
最大子矩阵和
最大子矩阵问题:
给定n(1<=n<=100)和一个nn(0< n <=100)的矩阵,请找到此矩阵的一个子矩阵,并且此子矩阵的各个元素的和最大,输出这个最大的值。
输入一个整数,然后输入nn个整数<128
Example:
4
0 -2 -7 0
9 2 -6 2
-4 1 -4 1
-1 8 0 -2
其中左上角的子矩阵:
9 2
-4 1
-1 8
此子矩阵的值为9+2+(-4)+1+(-1)+8=15。
这个题就要与上一个题相关联了
考虑二维的最大子矩阵问题
我们可以利用矩阵压缩把二维的问题转化为一维的最大子段和问题。因为是矩阵和,所以我们可以把这个矩形的高压缩成1行,进行相加然后进行挑选。
假设最大子矩阵的结果为从第r行到k行、从第i列到j列的子矩阵,如下所示(ari表示a[r][i],假设数组下标从1开始):
a11 …… a1i ……a1j ……a1n |
a21 …… a2i ……a2j ……a2n |
. . . . .
ak1 …… aki ……akj ……akn |
. . . . |
an1 …… ani ……anj ……ann |
那么我们将从第r行到第k行的每一行中相同列的加起来,可以得到一个一维数组如下:
(ar1+……+ak1, ar2+……+ak2, ……,arn+……+akn)
由此我们可以看出最后所求的就是此一维数组的最大子段和问题
poj1050:给一个n*n(1<=n<=100)的矩阵,求最大子矩阵和
思考:动态规划我遇到的最多的的就是求一个子欲裂,上升下降,或者一个上升另一个下降,,反复结合,但是做了这些题,最难的不是进行排序,而是如何计数和标记。