这里要求要走到终点再走回来,可以转化为两个人走。

那么我们可以先粗暴的设f[x1][y1][x2][y2]为第一个人走到(x1, y1), 第二个人走到(x2, y2)的最大价值。

那么这样空间会很大,通过观察可以发现,一个走的步数=横坐标+纵坐标,因为走一步一定是横坐标

或者纵坐标+1.

那么我们就可以转化为f[step][x1][x2],可以退出y1 = step - x1, y2 = step - x2

那么转移方程就很好求了

f[step][x1][x2] = max(f[step-1][x1-1][x2], f[step-1][x1-1][x2-1], f[step-1][x1][x2-1], f[step-1][x1][x2]) + a[i][step-i]

+ (i == j ? 0 : a[j][step-j])

这里要判断如果是同一个格子的话只加一次。

实际这样已经可以过了,代码如下

#include<cstdio>
#include<algorithm>
#define REP(i, a, b) for(int i = (a); i < (b); i++)
using namespace std; const int MAXN = 212;
int f[MAXN*2][MAXN][MAXN];
int a[MAXN][MAXN], n, m; void up(int& x, int a) { x = max(x, a); } int main()
{
scanf("%d%d", &m, &n);
REP(i, 1, n + 1)
REP(j, 1, m + 1)
scanf("%d", &a[i][j]);
REP(k, 2, n + m + 1)
{
for(int i = 1; i <= n && i + 1 <= k; i++)
for(int j = 1; j <= n && j + 1 <= k; j++)
{
for(int r1 = -1; r1 <= 0; r1++)
for(int r2 = -1; r2 <= 0; r2++)
up(f[k][i][j], f[k - 1][i + r1][j + r2]);
f[k][i][j] += a[i][k-i] + (i == j ? 0 : a[j][k-j]);
}
}
printf("%d\n", f[n + m][n][n]);
return 0;
}

但是呢其实空间上还可以更优化,因为只和k-1有关

那么我这里想到两种方法实现滚动数组。

第一个就是开两个二维数组,然后就来回更新。

#include<cstdio>
#include<algorithm>
#define REP(i, a, b) for(int i = (a); i < (b); i++)
using namespace std; const int MAXN = 212;
int f[2][MAXN][MAXN];
int a[MAXN][MAXN], n, m; void up(int& x, int a) { x = max(x, a); } int main()
{
scanf("%d%d", &m, &n);
REP(i, 1, n + 1)
REP(j, 1, m + 1)
scanf("%d", &a[i][j]);
int t = 0;
REP(k, 2, n + m + 1)
{
for(int i = 1; i <= n && i + 1 <= k; i++)
for(int j = 1; j <= n && j + 1 <= k; j++)
{
for(int r1 = -1; r1 <= 0; r1++)
for(int r2 = -1; r2 <= 0; r2++)
up(f[t][i][j], f[t ^ 1][i + r1][j + r2]);
f[t][i][j] += a[i][k-i] + (i == j ? 0 : a[j][k-j]);
}
t ^= 1;
}
printf("%d\n", f[t ^ 1][n][n]);
return 0;
}

还一种有点类似01背包逆推那个做法,只用一个数组就可以实现,改变循环顺序就好了。

为了让当前状态转移的时候,用来更新的值都是上一行的,所以我们要逆序来操作。

因为如果是从上到下,从左到右的话,要更新当前状态,需要用到f[i-1][j]等,而这个时候

f[i-1][j]之前已经算过了,已经更新过了,只要更新过了就成了这一行的值了,就不行。

所以我们要让f[i-1][j], f[i-1][j-1], f[i][j-1],f[i][j]都没有更新过。

所以我们就从下到上,从右到左来推,这样就可以保证都是上一行的值了。

#include<cstdio>
#include<algorithm>
#define REP(i, a, b) for(int i = (a); i < (b); i++)
using namespace std; const int MAXN = 212;
int f[MAXN][MAXN];
int a[MAXN][MAXN], n, m; void up(int& x, int a) { x = max(x, a); } int main()
{
scanf("%d%d", &m, &n);
REP(i, 1, n + 1)
REP(j, 1, m + 1)
scanf("%d", &a[i][j]);
REP(k, 2, n + m + 1)
{
for(int i = min(n, k - 1); i >= 1; i--)
for(int j = min(n, k - 1); j >= 1; j--)
{
for(int r1 = -1; r1 <= 0; r1++)
for(int r2 = -1; r2 <= 0; r2++)
up(f[i][j], f[i + r1][j + r2]);
f[i][j] += a[i][k-i] + (i == j ? 0 : a[j][k-j]);
}
}
printf("%d\n", f[n][n]);
return 0;
}

51nod 更难的矩阵取数问题 + 滚动数组优化的更多相关文章

  1. 51nod 更难的矩阵取数问题(动态规划)

    更难的矩阵取数问题 给定一个m行n列的矩阵,矩阵每个元素是一个正整数,你现在 在左上角(第一行第一列),你需要走到右下角(第m行,第n列),每次只能朝右或者下走到相邻的位置,不能走出矩阵.然后再从右下 ...

  2. [多路dp]更难的矩阵取数问题

    https://www.51nod.com/tutorial/course.html#!courseId=11&isCurrent=1 解题关键:1.注意i和j的最大取值都是n,k是i与j的和 ...

  3. 51Nod 1083 矩阵取数问题(矩阵取数dp,基础题)

    1083 矩阵取数问题 基准时间限制:1 秒 空间限制:131072 KB 分值: 5 难度:1级算法题 一个N*N矩阵中有不同的正整数,经过这个格子,就能获得相应价值的奖励,从左上走到右下,只能向下 ...

  4. 51Nod 1084 矩阵取数问题 V2 —— 最小费用最大流 or 多线程DP

    题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1084 1084 矩阵取数问题 V2  基准时间限制:2 秒 空 ...

  5. 51Nod 1084:矩阵取数问题 V2(多维DP)

    1084 矩阵取数问题 V2  基准时间限制:2 秒 空间限制:131072 KB 分值: 80 难度:5级算法题  收藏  关注 一个M*N矩阵中有不同的正整数,经过这个格子,就能获得相应价值的奖励 ...

  6. 【NOIP2007】矩阵取数

    因为傻逼写错高精度搞了一下午浪费好多时间,好想哭qaq 原题: 帅帅经常更同学玩一个矩阵取数游戏:对于一个给定的n*m的矩阵,矩阵中的每个元素aij据为非负整数.游戏规则如下: 1. 每次取数时须从每 ...

  7. P1005 矩阵取数游戏 区间dp 高精度

    题目描述 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n \times mn×m的矩阵,矩阵中的每个元素a_{i,j}ai,j​均为非负整数.游戏规则如下: 每次取数时须从每行各取走一个元素,共n ...

  8. 1084 矩阵取数问题 V2

    1084 矩阵取数问题 V2 基准时间限制:2 秒 空间限制:131072 KB 分值: 80 难度:5级算法题 一个M*N矩阵中有不同的正整数,经过这个格子,就能获得相应价值的奖励,先从左上走到右下 ...

  9. NOIP2007 矩阵取数游戏

    题目描述 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m的矩阵,矩阵中的每个元素aij均为非负整数.游戏规则如下: 1.每次取数时须从每行各取走一个元素,共n个.m次后取完矩阵所有元素: 2. ...

随机推荐

  1. Android实战技巧之三十七:图片的Base64编解码

    通经常使用Base64这样的编解码方式将二进制数据转换成可见的字符串格式,就是我们常说的大串.10块钱一串的那种,^_^. Android的android.util包下直接提供了一个功能十分完备的Ba ...

  2. Android之Http通信——1.初识Http协议

    Android之Http通信--1.初识Http协议 引言: 今天是六一儿童节,先在这里给各位超龄儿童说声节日快乐哈~( ╯□╰ ),小猪也象征性地给群里的小朋友们派了红包-嗯,忙碌的五月最终过去了, ...

  3. 在PyCharm中以root权限运行和调试python代码

    python中有的代码可能需要su权限,如 import os os.mkdir('/media/xxx/disk_a') 如果在交互式环境中使用,需要以sudo的方式启动python.而在PyCha ...

  4. Fast Flux技术——本质就是跳板,控制多个机器,同一域名指向极多的IP(TTL修改为0),以逃避追踪

    转自:http://ytuwlg.iteye.com/blog/355718 通过病毒邮件和欺诈网站学到的对付网络封锁的好东西:Fast Flux技术 收到一封邮件,引起我的好奇了: 邮件标题是:Ha ...

  5. tomcat到底是干什么用的?用大白话讲一下

    通俗点说他是jsp网站的服务器之一,就像asp网站要用到微软的IIS服务器,php网站用apache服务器一样,因为你的jsp动态网站使用脚本语言等写的,需要有服务器来解释你的语言吧,服务器就是这个功 ...

  6. 使用python抓取App数据

    App接口爬取数据过程使用抓包工具手机使用代理,app所有请求通过抓包工具获得接口,分析接口反编译apk获取key突破反爬限制需要的工具:夜神模拟器FiddlerPycharm实现过程首先下载夜神模拟 ...

  7. 了解Linux的基础知识和一般概念

    1.GNU和GPL    GNU计划(又称革奴计划),是由Richard Stallman(理查德·斯托曼)在1983年9月27日公开发起的自由软件集体协作计划.它的目标是创建一套完全自由的操作系统. ...

  8. [LNOI2014]LCA 树链剖分 离线 前缀和 思维题

    题目描述:给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1. 设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先. 有q次询问,每 ...

  9. 欢迎访问微先锋vXianFeng官方博客

    欢迎访问微先锋vXianFeng官方博客,专注微商城.P2P理财.山寨矿机平台研究与开发!

  10. 一个Web报表项目的性能分析和优化实践(三) :提高Web应用服务器Tomcat的内存配置,并确认配置正确

    摘要 上一篇,一个Web报表项目的性能分析和优化实践(一):小试牛刀,统一显示SQL语句执行时间 ,讲述了项目优化的整体背景,重点讲述了统一显示了Web项目SQL语句的执行时间. 本篇,将重点介绍提高 ...