传送门

这道题有好多好多种做法呀……先说一下最暴力的,O(n^4的做法)

我们相当于要找两条从左上到右下的路,使路上的数字和最大。所以其实路径从哪里开始走并不重要,我们就直接假设全部是从左上出发的好啦。设dp[i][j][p][q]表示第一条路枚举到点(i,j),第二条路枚举到点(p,q)时,当前能取到的最大值。

这样dp方程很显然,就是dp[i][j][p][q] = max(dp[i-1][j][p-1][q],dp[i][j-1][p-1][q],sp[i-1][j][p][q-1],dp[i][j-1][p][q-1]) + a[i][j] + a[p][q].如果i==p && j == q,那么减去一个a[i][j].最后dp[m][n][m][n]即为结果。

四层循环枚举,复杂度O(n^4),上一下代码。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define rep(i,a,n) for(ll i = a;i <= n;i++)
#define per(i,n,a) for(ll i = n;i >= a;i--)
#define enter putchar('\n') using namespace std;
const int M = ;
typedef long long ll; int read()
{
int ans = ,op = ;
char ch = getchar();
while(ch < '' || ch > '')
{
if(ch == '-') op = -;
ch = getchar();
}
while(ch >= '' && ch <= '')
{
ans *= ;
ans += ch - '';
ch = getchar();
}
return ans * op;
}
int m,n,dp[][][][],a[][];
int main()
{
m = read(),n = read();
rep(i,,m)
rep(j,,n) a[i][j] = read();
rep(i,,m)
rep(j,,n)
rep(p,,m)
rep(q,,n)
{
dp[i][j][p][q] = max(max(dp[i-][j][p-][q],dp[i-][j][p][q-]),max(dp[i][j-][p-][q],dp[i][j-][p][q-])) + a[i][j] + a[p][q];
if(i == p && j == q) dp[i][j][p][q] -= a[i][j];
}
printf("%d\n",dp[m][n][m][n]);
return ;
}

之后我们说一下怎么优化。两条路在走的时候,因为每次只能向右或者下走一格,所以两者必然是在同一条斜对角线上的(一条从右上到左下的对角线)那么我们就可以用对角线的横纵坐标和来表示当前DP到了哪里,之后每次只要枚举两个点的横坐标就可以把路径表示出来(也就是表示出来当前枚举的是哪两个点)。这样的话就可以把DP过程的时空降到三维的。

具体的写法也很简单,直接看一下代码即可。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<cstring>
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
#define enter putchar('\n')
using namespace std;
typedef long long ll;
const int M = ;
int n,m,f[M][M],dp[][M][M],q[M];
int read()
{
int ans = ,op = ;
char ch = getchar();
while(ch < '' || ch > '')
{
if(ch == '-') op = -;
ch = getchar();
}
while(ch >='' && ch <= '')
{
ans *= ;
ans += ch - '';
ch = getchar();
}
return ans * op;
} int main()
{
m = read(),n = read();
rep(i,,m)
rep(j,,n) f[i][j] = read();
rep(i,,n+m)
{
rep(p,,i-)
{
if(p > m) break;
rep(q,,i-)
{
if(q > m) break;
dp[i][p][q] = max(max(dp[i-][p][q-],dp[i-][p-][q]),max(dp[i-][p-][q-],dp[i-][p][q])) + f[p][i-p] + f[q][i-q];
if(p == q) dp[i][p][q] -= f[p][i-p];
}
}
}
printf("%d\n",dp[n+m][m][m]);
return ;
}

之后,时间复杂度基本已经不能再优化,不过空间复杂度却可以优化到O(n^2)(其实还要再乘以一个常数)

我们从刚才的三维DP的转移过程来考虑一下。每次DP都是从上一条对角线上的元素转移过来,和其他的对角线没有任何关系,相当于我们在每次DP的时候只需要考虑两个,一个是i,一个是i-1,在i-1之前的其实已经没有了任何作用。所以我们完全可以废物再利用。因为每次i的值只改变1,所以可以使用按位与的方法把它变成0或者1,之后直接dp即可,而最后的答案就是dp[(m+n)&1][m][m].这样空间复杂度又会降一维。本题的数据范围小,如果数据范围较大,滚动数组对于空间的节省就极为有用了。

看一下代码。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<cstring>
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
#define enter putchar('\n')
using namespace std;
typedef long long ll;
const int M = ;
int n,m,f[M][M],dp[][M][M];
int read()
{
int ans = ,op = ;
char ch = getchar();
while(ch < '' || ch > '')
{
if(ch == '-') op = -;
ch = getchar();
}
while(ch >='' && ch <= '')
{
ans *= ;
ans += ch - '';
ch = getchar();
}
return ans * op;
} int main()
{
m = read(),n = read();
rep(i,,m)
rep(j,,n) f[i][j] = read();
rep(i,,n+m)
{
rep(p,,i-)
{
if(p > m) break;
rep(q,,i-)
{
if(q > m) break;
int k = (i-)&;
dp[i&][p][q] = max(max(dp[k][p][q-],dp[k][p-][q]),max(dp[k][p-][q-],dp[k][p][q])) + f[p][i-p] + f[q][i-q];
if(p == q) dp[i&][p][q] -= f[p][i-p];
}
}
}
printf("%d\n",dp[(n+m)&][m][m]);
return ;
}

NOIP2008 传纸条(DP及滚动数组优化)的更多相关文章

  1. dp,滚动数组优化

    51Nod1084矩阵取数问题 V2 题意: 一个M*N矩阵中有不同的正整数,经过这个格子,就能获得相应价值的奖励,先从左上走到右下,再从右下走到左上.第1遍时只能向下和向右走,第2遍时只能向上和向左 ...

  2. NOIP2008传纸条[DP]

    题目描述 小渊和小轩是好朋友也是同班同学,他们在一起总有谈不完的话题.一次素质拓展活动中,班上同学安排做成一个m行n列的矩阵,而小渊和小轩被安排在矩阵对角线的两端,因此,他们就无法直接交谈了.幸运的是 ...

  3. HDU_1024.MaxSumPlusPlus(基础DP + 滚动数组优化讲解)

    这道题打破了我常规的做题思路,因为这是我刚开始训练DP,感觉这道题目好晕眼呀,emm其实就是感觉自己是真的菜...... 为什么说打破了我的做题思路呢,因为我平时看题解都是在已经AC或者完全不懂的情况 ...

  4. [BZOJ1044][HAOI2008]木棍分割 二分 + 单调队列优化dp + 滚动数组优化dp

    Description 有n根木棍, 第i根木棍的长度为Li,n根木棍依次连结了一起, 总共有n-1个连接处. 现在允许你最多砍断m个连接处, 砍完后n根木棍被分成了很多段,要求满足总长度最大的一段长 ...

  5. LG3004 「USACO2010DEC」Treasure Chest 区间DP+滚动数组优化

    问题描述 LG3004 题解 把拿走的过程反向,看做添加的过程,于是很显然的区间DP模型. 设\(opt_{i,j}\)代表区间\([i,j]\)中Bessie可以获得的最大值,显然有 \[opt_{ ...

  6. CodeForces 173C Spiral Maximum 记忆化搜索 滚动数组优化

    Spiral Maximum 题目连接: http://codeforces.com/problemset/problem/173/C Description Let's consider a k × ...

  7. 51nod 编辑距离 + 滚动数组优化

    这道题一开始觉得增加和删除会移动字符串的位置很不好做 两个字符串dp状态一般是第一个前i个和第二个前j个 #include<cstdio> #include<algorithm> ...

  8. HDU - 1024 Max Sum Plus Plus 最大m段子段和+滚动数组优化

    给定n个数字,求其中m段的最大值(段与段之间不用连续,但是一段中要连续) 例如:2 5 1 -2 2 3 -1五个数字中选2个,选择1和2 3这两段. dp[i][j]从前j个数字中选择i段,然后根据 ...

  9. poj1159 dp(滚动数组优化)

    H - 简单dp 例题扩展 Crawling in process... Crawling failed Time Limit:3000MS     Memory Limit:65536KB     ...

随机推荐

  1. Ubuntu 16.04安装Mac OS 12虚拟机资源(没成功,但资源还是可以用)

    整理的Mac OS 12虚拟机资源.装虚拟机基本是按这样的套路: 1.先装VM 2.破解VM使其支持Mac OS 12,这个脚本基本是全平台支持,可以看里面的教程文档. 3.用镜像安装系统. 资源: ...

  2. Free web scraping | Data extraction | Web Crawler | Octoparse, Free web scraping

    Free web scraping | Data extraction | Web Crawler | Octoparse, Free web scraping 人才知了

  3. 构建可读性更高的 ASP.NET Core 路由

    原文:构建可读性更高的 ASP.NET Core 路由 一.前言 不知你在平时上网时有没有注意到,绝大多数网站的 URL 地址都是小写的英文字母,而我们使用 .NET/.NET Core MVC 开发 ...

  4. dvm进程,linux进程,应用程序进程是否同一概念

    Android 运行环境主要指的虚拟机技术——Dalvik.Android中的所有Java程序都是运行在Dalvik VM上的.Android上的每个程序都有自己的线程,DVM只执行.dex的Dalv ...

  5. bsp开发之驱动开发

    驱动程序是可以管理虚拟设备或者物理设备,协议,服务等得软件模块,操作系统仅仅有通过驱动程序才干訪问硬件.针对windows ce开发设备驱动.就是通过platform builder创建一个新的平台, ...

  6. html5 式程序员表白

    html5 式程序员表白 王海庆 于 星期三, 04/06/2014 - 00:44 提交 今天是个好日子,2014年5月20日,表白的最佳时机,虽说孩子已经四岁.结婚已经五年.可是也不能够偷懒.于是 ...

  7. Hadoop教程(一)

    英文原文:cloudera,编译:ImportNew – Royce Wong Hadoop从这里开始!和我一起学习下使用Hadoop的基本知识,下文将以Hadoop Tutorial为主体带大家走一 ...

  8. TinyXML:属性

    TiXmlAttribute: 代表XML中的属性,TiXmlAttribute中定义了一系列对属性的操作 TiXmlAttribute的友元类: friend class TiXmlAttribut ...

  9. 深入理解JVM:HotSpot虚拟机对象探秘

    对象的创建 java是一门面向对象的语言.在Java程序执行过程中无时无刻有Java对象被创建出来.在语言层面上,创建对象(克隆.反序列化)一般是一个newkeyword而已,而在虚拟机中,对象的创建 ...

  10. glGenLists返回0或None的原因

    最近调用PyOpenGL做显示,想在程序启动时候调用Display List进行显示,但是glGenLists返回None,若在程序启动后调用则没有任何问题. 搜索谷歌后,给出的解释: This ca ...