传送门

这道题有好多好多种做法呀……先说一下最暴力的,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 ;
}

最新文章

  1. JavaScript模板引擎artTemplate.js——结语
  2. DotnetCore Docker
  3. Excel 回归分析
  4. 线性时间内确定T[0:n]是否有一个主元素
  5. 使用AngularJS构建大型Web应用
  6. 数据库不能用delete---index空间不足
  7. [PHP]htmlentities() 函数
  8. 2个或多个datable类似于sql inner join 合并查询
  9. VMware GSX Server 3.2.1 Build 19281免费下载
  10. win8及win8.1商店出现0X80073CF9的解决办法!
  11. cin 与 scanf 的不同
  12. spy++捕获窗口消息
  13. 【转】vs2017快捷键大全
  14. (转)python生态环境简介
  15. Codeforces#543 div2 B. Mike and Children(暴力?)
  16. wz
  17. 支付宝(alipay)即时到账收款接口开发中的那些事儿
  18. 【Java】-NO.16.EBook.4.Java.1.008-【疯狂Java讲义第3版 李刚】- 集合/容器
  19. Java @Repeatable
  20. 【转】Java学习---集合框架那些事

热门文章

  1. mysql主从库
  2. luogu P1149 火柴棒等式
  3. codevs 2669 简单的试炼
  4. Ubuntu使用iptables配置防火墙提示:unrecognized service(Ubuntu配置iptables防火墙)
  5. centos 安装php缓存 apc或zend-opcode
  6. java并发编程阻塞队列
  7. Linux MySQL主从复制(Replication)配置
  8. WCF服务端的.NET Core支持项目Core WCF 正式启动
  9. linux学习:进程间通信—管道
  10. Mac OS用minikube安装单节点kubernetes