动态规划

动态规划:分阶段求取最优解的问题,在一些简单的题中直接就是递归运算
动态规划每一个阶段都有与之相对应的状态,都面临着不同的抉择
特别是要想办法分成若干个子问题来进行分解寻找最优解。
所以现在要行办法获得递归关系式

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)的矩阵,请找到此矩阵的一个子矩阵,并且此子矩阵的各个元素的和最大,输出这个最大的值。
输入一个整数,然后输入n
n个整数<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)的矩阵,求最大子矩阵和

思考:动态规划我遇到的最多的的就是求一个子欲裂,上升下降,或者一个上升另一个下降,,反复结合,但是做了这些题,最难的不是进行排序,而是如何计数和标记。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值