极简的dp代码

设有N*N的方格图(N<=10,我们将其中的某些方格中填入正整数,而其他的方格中则放入数字0。如下图所示(见样例):

某人从图的左上角的A 点出发,可以向下行走,也可以向右走,直到到达右下角的B点。在走过的路上,他可以取走方格中的数(取走后的方格中将变为数字0)。

此人从A点到B 点共走两次,试找出2条这样的路径,使得取得的数之和为最大。

输入描述 Input Description

输入的第一行为一个整数N(表示N*N的方格图),接下来的每行有三个整数,前两个表示位置,第三个数为该位置上所放的数。一行单独的0表示输入结束。
输出描述 Output Description

只需输出一个整数,表示2条路径上取得的最大的和。

样例输入 Sample Input

  8

  2  3  13

  2  6   6

  3  5   7

  4  4  14

  5  2  21

  5  6   4

  6 3  15

  7 2  14

  0 0  0

样例输出 Sample Output

  67

数据范围及提示 Data Size & Hint
如描述

作为一道比较简单的dp题,只要列好状态方程然后就可以求解了。
于是第一遍我就傻乎乎的直接写了,直到看到了下面那段极简轻奢的代码

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int n,x,y,v;
int f[11][11][11][11];//用于记录经由x1,y1,x2,y2,到达该点的最大取值
int a[11][11];//很简单的保存一下地图
int main()
{
    scanf("%d",&n);
    while (true)
    {
        scanf("%d%d%d",&x,&y,&v);
        if(x==0)   break;
        a[x][y]=v;
    }//输入,很简单,不解释
    for(int x1=1;x1<=n;x1++)
      for(int y1=1;y1<=n;y1++)
         for(int x2=1;x2<=n;x2++)
            for(int y2=1;y2<=n;y2++)//由于本题数据比较小,可以允许如此暴力的进行枚举
               {
                   f[x1][y1][x2][y2]=max(max(f[x1-1][y1][x2-1][y2],f[x1-1][y1][x2][y2-1]),max(f[x1][y1-1][x2-1][y2],f[x1][y1-1][x2][y2-1]))+a[x1][y1]+a[x2][y2];
                   //重点来了,先取路径1从左边来时,路径2从左边来和从上边来的较大值,同时也取路径1从上边来,路径2从左边和上边两种情况下的最大值,接着再取最大值
                  //等于得到了到达这一步前可能取得的最大值,然后加上这一点的权值,即为这一点的最大取值
                   if(x1==x2&&y1==y2)                    //x1,y1控制前一条路径  x2,y2控制后一条路径
                     f[x1][y1][x2][y2]-=a[x1][y1];//若两条路径的数值相同,说明其为同一条路径,其数值只能加一遍,然而前面两条路径相同时,并没有考虑取完之后该方格为空,所以要额外减去
               }//输出两条路径的和
    int ans=f[n][n][n][n];//输出不解释
    printf("%d",ans);
    return 0;
}

题目很简单,但是能写到如此精简,也是不易。
提醒我,能用循环写的dp一定不要用递归。
另外,多维数组是可以用来保存状态的,而且很好用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值