写三次丢失两次,我谔谔,以后再不在博客园先保存我就去死

题目内容

洛谷链接

小渊和小轩是好朋友也是同班同学,他们在一起总有谈不完的话题。一次素质拓展活动中,班上同学被安排坐成一个\(m\)行、\(n\)列的矩阵,而小渊和小 轩被安排坐在矩阵对角线的两端,因此,他们就无法直接交谈了。幸运的是,他们可以通过传纸条来进行交流。纸条要经由许多同学传到对方手里,小渊坐在矩阵的左上角,坐标\((1,1)\),小轩坐在矩阵的右下角,坐标\((m,n)\)。从小渊传给小轩的纸条只可以向下或者向右传递,从小轩传给小渊的纸条只可以向上或者向左传递。

在活动进行中,小渊希望给小轩传一张纸条,同时希望小轩给他回复。班里的每个同学都可以帮他们传递,但只会帮他们一次,也就是说如果此人在小渊递给小轩纸条的时候帮忙,那么在小轩递给小渊的时候就不会再帮忙。反之亦然

还有一件事情需要注意,全班每个同学愿意帮忙的好心程度有高有低(注意:小渊和小轩的好心程度没有定义,输入时用\(0\)表示),可以用一个\(0-100\)的自然数来表示,数越大表示越好心。小渊和小轩希望尽可能找好心程度高的同学来帮忙传纸条,即找到来回两条传递路径,使得这两条路径上同学的好心程度之和最大。现在,请你帮助小渊和小轩找到这样两条路径。

输入格式

第一行有两个用空格隔开的整数\(m\)和\(n\),表示班里有\(m\)行\(n\)列\((1\le m,n\le 50)\)。

接下来的\(m\)行是一个\(m×n\)的矩阵,矩阵中第\(i\)行\(j\)列的整数表示坐在第\(i\)行\(j\)列的学生的好心程度。每行的\(n\)个整数之间用空格隔开。

输出格式

共一行,包含一个整数,表示来回两条路上参与传纸条的同学的好心程度之和的最大值。

样例输入

3 3

0 3 9

2 8 5

5 7 0

样例输出

34

思路

更加简单的一道P1004 方格取数

双倍经验啊

四维

时间复杂度\(O(n^2×m^2)\),其实已经能水过了因为范围挺小的orz。

用\(f[i][j][k][q]\)表示第一张纸条传到\((i,j)\),第二张纸条传到\((k,q)\)所累计下来的好心程度总和。

对于每一步有四种情况:

  • 第一张纸条向下传,第二张纸条向下传;
  • 第一张纸条向下传,第二张纸条向右传;
  • 第一张纸条向右传,第二张纸条向下传;
  • 第一张纸条向右传,第二张纸条向右传;

\(f[i][j][k][q]=max\{f[i][j-1][k-1][q],f[i-1][j][k][q-1],f[i][j-1][k][q-1],f[i-1][j][k-1][q]\}+a[i][j]+a[k][q]\)

注意要求两条路线严格不重合,所以为了防止重复q的范围应该是\(j+1\)到\(m\)。或者手动判断重复的时候减去一个。

代码

#include <bits/stdc++.h>
using namespace std;
const int maxn=55;
int n,m;
int f[maxn][maxn],a[maxn][maxn]; int mymax(int a,int b,int c,int d){
return max(max(max(a,b),c),d);
} int main(){
scanf("%d%d",&n,&m); for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&a[i][j]); for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
for(int k=1;k<=n;k++)
for(int q=j+1;q<=m;l++)
f[i][j][k][q]=mymax(f[i][j-1][k-1][q],f[i-1][j][k][q-1],f[i][j-1][k][q-1],f[i-1][j][k-1][q])+a[i][j]+a[k][q]; printf("%d",f[n][m-1][n-1][m]);
return 0;
}

式子太长辣有可能鬼畜辣QAQ

三维

进阶版

时间复杂度\(O(n^2×(n+m))\)

可以发现每次转移两个纸条走过的路程总是相等的。即\(i+j=k+q\)。

设\(i+j=k+q=step\),我们枚举\(step\),同时枚举第一个人和第二个人的横坐标或者纵坐标,另一个就可以算出来了,例如枚举横坐标。

\(f[k][i][j]=max\{f[k-1][i][j],f[k-1][i-1][j-1],f[k-1][i][j-1],f[k-1][i-1][j]\}+a[i][k-i+1]+a[j][k-j+1]\)

不过要注意的是枚举步数的一维要开两倍大小,否则RE的美滋滋,同时要手动判重。

代码

#include <bits/stdc++.h>
using namespace std;
const int maxn=55;
int n,m;
int f[2*maxn][maxn][maxn],a[maxn][maxn];
int mymax(int a,int b,int c,int d){
return max(max(max(a,b),c),d);
}
int main(){
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
scanf("%d",&a[i][j]); for (int k=1;k<=n+m-1;k++)
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++){
if (k-i+1<1||k-j+1<1)continue;//判断纵坐标的合法性
f[k][i][j]=mymax(f[k-1][i][j],f[k-1][i-1][j-1],f[k-1][i][j-1],f[k-1][i-1][j])+a[i][k-i+1]+a[j][k-j+1];
if(i==j)//重合删掉一个(若数据中有负数则不能这么判重!)
f[k][i][j]-=a[i][k-i+1];
}
printf("%d\n",f[n+m-1][n][n]);
return 0;
}

二维

其实就是滚动数组优化辣,时间不变,但是空间会小很多。

在三维中,我们可以看出状态的转移只和上一行有关,所以可以想到滚动数组。

去重方法就是使\(j>i\)(比较显然吧)。

(不知为何\(maxn\)设成55会WA \(n=50,m=50\) 的点,改成210才行,为了调这个感觉都要成浪费学校评测机资源了)

代码

#include <bits/stdc++.h>
using namespace std;
const int maxn=210;
int n,m;
int f[maxn][maxn],a[maxn][maxn]; int mymax(int a,int b,int c,int d){
return max(max(max(a,b),c),d);
} int main(){
//freopen("1.txt","r",stdin);
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
scanf("%d",&a[i][j]); for (int k=1;k<=n+m-1;k++)
for (int i=n;i>=1;i--)
for (int j=n;j>i;j--)
f[i][j]=mymax(f[i][j],f[i-1][j-1],f[i][j-1],f[i-1][j])+a[i][k-i+1]+a[j][k-j+1]; printf("%d\n",f[n-1][n]);
return 0;
}

写完本篇题解心态已经崩了

UPD:附日常解法(大家都这么写的诶orz):

#include <bits/stdc++.h>
using namespace std;
const int maxn=55;
int m,n;
int a[maxn][maxn];
int f[maxn][maxn][maxn][maxn]; int main(){
scanf("%d%d",&m,&n);
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
scanf("%d",&a[i][j]); for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
for(int k=1;k<=m&&i+j>k;k++){
int q=i+j-k;
if(i==k)
f[i][j][k][q]=max(max(max(f[i-1][j][k-1][q],f[i][j-1][k-1][q]),f[i-1][j][k][q-1]),f[i][j-1][k][q-1])+a[i][j];
else
f[i][j][k][q]=max(max(max(f[i-1][j][k-1][q],f[i][j-1][k-1][q]),f[i-1][j][k][q-1]),f[i][j-1][k][q-1])+a[i][j]+a[k][q];
}
}
} printf("%d",f[m][n][m][n]);
return 0;
}

最后这个代码块的高亮没了?我谔谔

最新文章

  1. Nginx配置location总结及rewrite规则写法
  2. GZip压缩的js文件IE6下面不能包含&lt;script&gt;标签
  3. Java基础之线程——使用执行器(UsingExecutors)
  4. lambda形式(转)
  5. javacc
  6. Unique Binary Search Trees In JAVA
  7. Caffe Ubuntu14.04 64位 的最快安装 (cuda7.5 + cudnn7.0 2016最新)
  8. Android_Jar mismatch! Fix your dependencies
  9. PS 图像调整算法——自动对比度 (Auto Contrast)
  10. 后端开发者的Vue学习之路(四)
  11. 分布式Tomcat session会话Sticky Sessions问题
  12. oracle去掉字符串中所有指定字符
  13. DPI 计算及速查表
  14. Popush End
  15. sql sever读取写入Excel总结
  16. 关于YII中layout中的布局和view中数据的关系
  17. Android中关于JNI 的学习(五)在C文件里使用LogCat
  18. layer模态窗简单使用
  19. android - px(像素)、dpi(像素密度)、dip(密度无关像素)之间的关系
  20. Tarjan的LCA离线算法

热门文章

  1. python django 简单接口测试页面
  2. Traveling by Stagecoach(POJ 2686)
  3. JVM-垃圾回收篇
  4. 我搭建了一套企业级私有Git服务,抗住了每天上万次攻击!
  5. 面试官:一个 TCP 连接可以发多少个 HTTP 请求?
  6. 安装了高版本OS X 之后无法使用MacPorts的port命令
  7. Centos-实时监控系统处理器状态-top
  8. Go-注释
  9. centos7卸载mariadb安装mysql
  10. 【题解】CF1324F