这道题很有趣,暴搜的时间复杂度太过于凶残O(K*(2^n)^2)(K的意思是大常数),不过作为提高组T4,这道题数据范围太小了,感觉哪怕是离谱的暴搜也能过。

再加上一时半会没想好多项式时间复杂度的正解DP,就搞了一个四不像出来,第一次走用搜索来实现第二次走用记搜来实现,这样时间复杂度就是O((2^n)*(n^2)),仍然很凶残但毕竟数据太水了。这个做法很简单,对于现在的我来说简直是基本功了,五十行代码很快便写好然后轻松调了调就AC了

但显然我还是要想想正解的,初步想了一下没想出来便看了眼题解,没看懂题解的思路讲解但是看了眼代码后,瞬间想到了以下内容便理解了整个过程。

此前考虑到第一次搜索会影响第二次搜索而第一次搜索后的结果用状态来描述就要用n个坐标这会导致dp的时间复杂度变为n^n从而使得dp毫无意义。

但是,后来意识到如果同步处理两次移动,用一个四个坐标(即两人坐标)的dp来刻画一个状态,这是他们走的第几步即他们所在那一圈这两个数据显然都隐含在坐标中而且由于状态转移过程中不会改变两人总步数的差且结尾状态两人总步数的差是0!!!这就导致我需要求的那部分的dp两人总步数的差始终为0!!!也就是说两人始终走过总路程相同,他们在同一条“带”上,这意味着根本不需要存某个人走过了哪些步来一一对照,只需要在每一步考虑他们是否在同一带上选择了同一格即可!如果选择了同一格,那去掉重复加了的得分即可。

甚至,由于两人总路程相同,而总路程+两人x坐标可以推导出两人y坐标,所以用总路程+两个x坐标就可以足以刻画状态,就这般,三维DP即可解决问题!

妙哉

思路已经完全清晰,没什么可说的了,也没什么浪费时间写出来的必要了,毕竟想明白以上内容后想写简直太简单了,在这里复制一段别人写的四维dp代码和三维dp代码,仅供参考。

O((2^n)*(n^2))-Code

#include <iostream>
#include <cstring> using namespace std;
int ans,dp[10][10],N,x,y,z,a[10][10],b[10][10];
int dpdfs(int x,int y)
{
if(x<1||y<1)return -99999999;
if(x==1&&y==1)return dp[1][1]=0;
if(dp[x][y]!=-1)return dp[x][y];
int DFS=max(dpdfs(x-1,y),dpdfs(x,y-1));
if(b[x][y]==0)DFS+=a[x][y];
return dp[x][y]=DFS;
}
void dfs(int x,int y,int l)
{
if(x>N||y>N)return;
if(x==N&&y==N)
{
memset(dp,-1,sizeof(dp));
ans=max(ans,l+dpdfs(N,N));
return;
}
b[x+1][y]=1;dfs(x+1,y,l+a[x+1][y]);b[x+1][y]=0;
b[x][y+1]=1;dfs(x,y+1,l+a[x][y+1]);b[x][y+1]=0;
return;
} int main()
{
cin>>N;
while(cin>>x>>y>>z)
{
if(x==0&&y==0&&z==0) break;
a[x][y]=z;
}
b[1][1]=1;
dfs(1,1,a[1][1]);
cout<<ans<<endl;
return 0;
}

O(n^4)-Code

#include<bits/stdc++.h>
using namespace std;
const int maxn=10;
int a[maxn][maxn],f[maxn<<1][maxn][maxn],n;
int main()
{
scanf("%d",&n);
memset(a,0,sizeof(a));
while (1)
{
int x,y,z;
scanf("%d %d %d",&x,&y,&z);
if (x==0 && y==0 && z==0) break;
a[x][y]=z;
}
f[0][1][1]=a[1][1];//初始化
for (int i=1;i<=2*n-2;i++)//因为最多走2n-2步,x1+x2=i+2
for (int x1=1;x1<=n;x1++)
for (int x2=1;x2<=n;x2++)
{
int y1=i+2-x1,y2=i+2-x2;//算出纵坐标
if (y1<1 || y2<1) continue;//判断是否越界
f[i][x1][x2]=max(f[i-1][x1][x2],max(f[i-1][x1-1][x2],max(f[i-1][x1][x2-1],f[i-1][x1-1][x2-1])))+a[x1][y1]+a[x2][y2];//上面说的转移
if (x1==x2 && y1==y2) f[i][x1][x2]-=a[x1][y1]; //如果走到同一个点就减一次
}
printf("%d",f[n*2-2][n][n]);//目标状态
return 0;
}

O(n^3)-Code

#include<bits/stdc++.h>
using namespace std;
const int maxn=10;
int a[maxn][maxn],f[maxn<<1][maxn][maxn],n;
int main()
{
scanf("%d",&n);
memset(a,0,sizeof(a));
while (1)
{
int x,y,z;
scanf("%d %d %d",&x,&y,&z);
if (x==0 && y==0 && z==0) break;
a[x][y]=z;
}
f[0][1][1]=a[1][1];//初始化
for (int i=1;i<=2*n-2;i++)//因为最多走2n-2步,x1+x2=i+2
for (int x1=1;x1<=n;x1++)
for (int x2=1;x2<=n;x2++)
{
int y1=i+2-x1,y2=i+2-x2;//算出纵坐标
if (y1<1 || y2<1) continue;//判断是否越界
f[i][x1][x2]=max(f[i-1][x1][x2],max(f[i-1][x1-1][x2],max(f[i-1][x1][x2-1],f[i-1][x1-1][x2-1])))+a[x1][y1]+a[x2][y2];//上面说的转移
if (x1==x2 && y1==y2) f[i][x1][x2]-=a[x1][y1]; //如果走到同一个点就减一次
}
printf("%d",f[n*2-2][n][n]);//目标状态
return 0;
}

以上、

P1004-DP【绿】的更多相关文章

  1. 「疫期集训day4」硝烟

    那真是一阵恐怖的炮击(that boomed booms),响亮的炮音(that noise),滚滚的硝烟(that smoke),熊熊的火焰在围绕着我们前进...小心前进(go and be car ...

  2. 洛谷 P1004 方格取数 【多进程dp】

    题目链接:https://www.luogu.org/problemnew/show/P1004 题目描述 设有N*N的方格图(N<=9),我们将其中的某些方格中填入正整数,而其他的方格中则放 ...

  3. 洛谷 - P1004 - 方格取数 - 简单dp

    https://www.luogu.org/problemnew/show/P1004 这道题分类到简单dp但是感觉一点都不简单……这种做两次的dp真的不是很懂怎么写.假如是贪心做两次,感觉又不能证明 ...

  4. 棋盘DP三连——洛谷 P1004 方格取数 &&洛谷 P1006 传纸条 &&Codevs 2853 方格游戏

    P1004 方格取数 题目描述 设有N $\times N$N×N的方格图(N $\le 9$)(N≤9),我们将其中的某些方格中填入正整数,而其他的方格中则放入数字00.如下图所示(见样例): A ...

  5. P1004 方格取数(四维dp)

    P1004 方格取数 思路如下 这题是看洛谷大佬的思路才写出来的,所以我会把大佬的思路展示如下: 1⃣️:我们可以找到一个叫思维dp的东西,dp[i][j][k][l],其中前两维表示一个人从原点出发 ...

  6. P1004 方格取数——奇怪的dp

    P1004 方格取数 题目描述 设有 \(N\times N\) 的方格图 \((N\leq 20)\),我们将其中的某些方格中填入正整数,而其他的方格中则放入数字 \(0\) .如下图所示(见样例) ...

  7. 洛谷P1004 方格取数-四维DP

    题目描述 设有 N \times NN×N 的方格图 (N \le 9)(N≤9) ,我们将其中的某些方格中填入正整数,而其他的方格中则放入数字 00 .如下图所示(见样例): A 0 0 0 0 0 ...

  8. Luogu P1004/P1006 方格取数/传纸条 【棋盘Dp】 By cellur925

    我明明记得写过这篇啊qwq为什么会搞丢 两题几乎一样. 如果再拓展到k条路,就要用网络流跑了,本蒟现在还不会. 我们容易想到四维dp,但是有一种更好的方法. 首先,先从左上到右下.再从右下到左上可以近 ...

  9. P1004 方格取数[棋盘dp]

    题目来源:洛谷 题目描述 设有N×N的方格图(N≤9),我们将其中的某些方格中填入正整数,而其他的方格中则放入数字0.如下图所示(见样例): A 0 0 0 0 0 0 0 0 0 0 13 0 0 ...

  10. 洛谷 P1004 方格取数 【多线程DP/四维DP/】

    题目描述(https://www.luogu.org/problemnew/show/1004) 设有N*N的方格图(N<=9),我们将其中的某些方格中填入正整数,而其他的方格中则放 人数字0. ...

随机推荐

  1. 用元编程来判断STL类型

      在此之前,先来回顾元编程当中的一个重要概念. template<typename _Tp, _Tp __v> struct integral_constant { static con ...

  2. SpringCloudGateway解决跨域问题

    1.跨域问题详情 2.为什么会跨域? 官方定义:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CORS 怎么出现的? 1.浏览器访问了一个业务 h ...

  3. Android对接微信登录记录

    Android对接微信登录记录 - Stars-One的杂货小窝 Android项目要对接下微信登录,稍微记录下踩坑点 代码 1.添加依赖 implementation 'com.tencent.mm ...

  4. 华企盾DSC客户端图标不显示常见处理方法

    1.检查是否启用了360桌面.猎豹桌面之类的(兼容腾讯桌面),打强制显示客户端图标的补丁 2.是否被杀毒软件查杀 3.用Autoruns查看explorer项图标那一栏前10个是否有我们图标没有的话把 ...

  5. 踩坑ffmpeg录制的mp4无法在浏览器上播放

    前言 使用ffmpeg编译好的程序在电脑上进行音视频转换,可以参考这篇:<windows电脑FFmpeg安装教程手把手详解_windows安装ffmpeg>,而我们要做的是在游戏引擎中集成 ...

  6. P3537 [POI2012]SZA-Cloakroom 题解

    题目大意 有 \(n\) 件物品,每件物品有三个属性 \(a_i, b_i, c_i (a_i < b_i)\). 再给出 \(q\) 个询问,每个询问由非负整数 \(m, k, s\)组成,问 ...

  7. 一文了解 Kubernetes

    一文了解 Kubernetes 简介:Docker 虽好用,但面对强大的集群,成千上万的容器,突然感觉不香了.这时候就需要我们的主角 Kubernetes 上场了,先来了解一下 Kubernetes ...

  8. spring-mvc 系列:域对象共享数据

    目录 一.使用ServletAPI向request域对象共享数据 二.使用ModelAndView向request域对象共享数据 三.使用Model向request域对象共享数据 四.使用Map向re ...

  9. Quartz.Net系列(一):Windows任务计划程序

    1.使用此电脑=>管理  系统工具=>任务计划程序=>任务计划程序库=>创建任务  创建任务  触发器  操作  条件=>去掉只有在计算机使用交流电源时才启动此任务 创建 ...

  10. 云图说|图解云消息服务KooMessage

    摘要:云消息服务(KooMessage)是提供数字化营销新入口,覆盖全行业.全场景.全终端的一站式富媒体消息服务. 本文分享自华为云社区<[开天aPaaS]图解云消息服务KooMessage&g ...