DP算法题目的心得

第一:先将题目化简

第二:建立数组dp[i][j],给dp[i][j]赋予意义

第三:计算出dp[0][0],dp[0][1],dp[0][2],dp[1][0],dp[1][1],dp[1][2],dp[2][0],dp[2][1],dp[2][2]观察他们之间的关系变化,观察每次增加数据量的变化

第四:将最容易得到的dp[i][j]进行赋值

第五:用双重循环给dp[i][j]进行赋值

这里拿出一道例题进行对应分析:

试题 算法训练 拿金币

问题描述

  有一个N x N的方格,每一个格子都有一些金币,只要站在格子里就能拿到里面的金币。你站在最左上角的格子里,每次可以从一个格子走到它右边或下边的格子里。请问如何走才能拿到最多的金币。

输入格式

  第一行输入一个正整数n。
  以下n行描述该方格。金币数保证是不超过1000的正整数。

输出格式

  最多能拿金币数量。

样例输入

3
1 3 3
2 2 2
3 1 2

样例输出

11

数据规模和约定

  n<=1000

第一步将题目简化:

将题目简化为:

2
1 3 
2 2 

第二步:建立数组dp[i][j],给dp[i][j]赋予意义:

建立一个dp[i][j],根据题目为其赋予意义

这里dp[i][j]被赋予的意义是,在第i行第j列最多能拿金币数量

第三步:计算出dp[0][0],dp[0][1],dp[0][2],dp[1][0],dp[1][1],dp[1][2],dp[2][0],dp[2][1],dp[2][2]观察他们之间的关系变化,观察每次增加数据量的变化:

dp[1][1]=1    ,dp[1][2]=1+3

dp[2][1]=1+2,dp[2][2]=3+2

很容易观察到dp[2][2]=max(dp[2-1][2],dp[2][2-1])+第i行第i列格子里面的金币

很容易可以将dp[2][2]推广到dp[i][j]

即:

dp[i][j]=max(dp[i-1][j],dp[i][j-1]+第i行第i列格子里面的金币

 第四:将最容易得到的dp[i][j]进行赋值:

很容易得出:dp[0][j]=0,dp[i][0]=0;

检验一下:dp[1][1]=max(dp[0][1],dp[1][0])+第1行第1列格子里面的金币=0+1=1

               dp[1][2]=max(dp[0][2],dp[1][1])+第1行第2列格子里面的金币=1+3=4

               dp[2][1]=max(dp[1][1],dp[2][0])+第2行第1列格子里面的金币=1+2=3

               dp[2][2]=max(dp[1][2],dp[2][1]+第2行第2列格子里面的金币

                           =max(4,3)+2=6

满足实际

第五:用双重循环给dp[i][j]进行赋值:

再进行给dp[i][j]赋值之前,还有  “第i行第j列格子里面的金币”  这个数据没有表示出来

用数组a[i][j]表示 第i行第j列格子里面的金币

即:

for(i=1;i<=n;i++){
    for(j=1;j<=n;j++){
    scanf("%d",&x);
    a[i][j]=x;
    }
}

再给dp[i][j]进行赋值:

for(i=1;i<=n;i++){
    for(j=1;j<=n;j++){
    dp[i][j]=max(dp[i-1][j]+dp[i][j-1])+a[i][j];
        }
    }

 这里附上完整代码:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int a[1001][1001];
int dp[1001][1001];
/* run this program using the console pauser or add your own getch, system("pause") or input loop */


int max(int a,int b){
    return a>b?a:b;
}


int main(int argc, char *argv[]) {

    int i,j,n,x;
    scanf("%d",&n);
    for(i=1;i<=n;i++){
        for(j=1;j<=n;j++){
        scanf("%d",&x);
        a[i][j]=x;
        }
    }
    for(i=0;i<=n;i++){
        dp[0][i]=0;
        dp[i][0]=0;
    }
    for(i=1;i<=n;i++){
        for(j=1;j<=n;j++){
        dp[i][j]=max(dp[i-1][j],dp[i][j-1])+a[i][j];
        }
    }
    printf("%d",dp[n][n]);
	return 0;
}

总结归纳:动态规划的难点在于设计dp[i][j]的含义和发现dp[i][j]中i,j逐渐变大,dp[i][j]所发生的规律变化,即dp[i][j]和i,j之前数据发生的变化,这个变化要简单,容易总结。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值