这道题很有趣,暴搜的时间复杂度太过于凶残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. .NET Conf China 2023 活动纪实 抢先看

    ​ 今天2023年12月16日.NET Conf China 2023举办的日子,北京昨天上午还在飘起雪花,到今天早上的天气就有了极大的改观,大清早就能看到外面徐徐升起的朝阳,这也预示着今天将是一个大 ...

  2. Python——第一章:占位——pass

    pass: 常用于代码占位 a = 10 if a > 100: pass 当设计代码时,有些条件或代码还没有想好要如何处理,先用pass做占位,后续可以回来继续写.如果不写pass则会报错,因 ...

  3. CentOS系统中yum的基本用法

    最小化安装系统时,yum可能会因为网卡配置问题,随机启动配置,导致无法使用, 在shell里面输入:yum --help ,结果显示 yum 已经正常安装了!!到底是哪里出了问题呢?经过网友的提示,我 ...

  4. C realloc(): invalid next size错误

    C realloc(): invalid next size 问题代码 #include <stdio.h> #include <stdlib.h> int *getNumbe ...

  5. QRCoder1.4.3生成二维码,不依赖System.Drawing,解决"未能找到类型或命名空间名QRCode","及ImageFormatPng仅在windows上受支持"

    生成二维码1(简单) 包引用: <PackageReference Include="QRCoder" Version="1.4.3" /> usi ...

  6. React jsx 语法解析 & 转换原理

    jsx介绍 jsx是一种JavaScript的语法扩展(eXtension),也在很多地方称之为JavaScript XML,因为看起就是一段XML语法,用于描述UI界面,并且可以和JavaScrip ...

  7. ChatGPT新玩法来了,微信聊天机器人

    前言 上一篇文章中说了ChatGPT是什么,然后怎么注册使用. 传送门:花了1块钱体验一把最近很火的ChatGPT 但是实际操作下来还是有不少小伙伴跟我一样遇到各种坑. 没有魔法工具 OpenAI的服 ...

  8. .NET Conf China 2023分享-.NET应用国际化-AIGC智能翻译+代码生成

    今年.NET Conf China 2023技术大会,我给大家分享了 .NET应用国际化-AIGC智能翻译+代码生成的议题,今天整理成博客,分享给所有人. 随着疫情的消退,越来越多的企业开始向海外拓展 ...

  9. 经验说丨华为云视频Cloud Native架构下实践

    摘要:来自华为云直播的段亮详细介绍华为云视频在Cloud Native的转型实践中遇到的问题.挑战以及解决之道. 随着云基础设施服务以及边缘计算技术的发展,Cloud Native,即云原生,架构理念 ...

  10. Python 初学者必看:Python 异常处理集合

    摘要:作为 Python 初学者,在刚学习 Python 编程时,经常会看到一些报错信息,本文专门介绍 python 异常处理. 异常 广义上的错误分为错误和异常 错误指的是可以人为避免 异常是指在语 ...