【GDKOI2013】贪吃蛇 题解

news/2024/6/16 2:48:57 标签: 动态规划, 算法, c++

题目大意:

给出一张大小为 n ∗ m n*m nm 的矩阵,每一块都有一个权值 a i , j a_{i,j} ai,j ,可以随机选择起点,并且只能向右拐或向前走,不能碰到走过的路或走出图,求走过的路径权值和最大为多少。

数据范围:

1 ≤ n , m ≤ 32 , ∣ a i , j ∣ ≤ 1 0 4 1 \le n,m \le 32 , |a_{i,j}| \le 10^4 1n,m32,ai,j104

思路:

转移方程非常阴间。。。
看到数据范围 n , m ≤ 32 n,m \le 32 n,m32 发现使用搜索时间上过不去,所以考虑使用 D P DP DP
我们可以发现所有合法的路径一定包含一个或两个回环,如图:
在这里插入图片描述
所以我们可以先 D P DP DP 求出所有的回环,再将回环拼接在一起就可以了。
可以发现每一个回环的区别有:
1. 1. 1. 顺时针和逆时针(如图2的两个回环)
2. 2. 2. 结束的点(如图1在右下角,图2第一个回环在右下角,第二个回环在左下角)

所以可以设 f x , y , x x , y y , 0 / 3 , 0 / 1 f_{x,y,xx,yy,0/3,0/1} fx,y,xx,yy,0/3,0/1 表示这个回环是在左上角为 ( x , y ) (x,y) (x,y) ,右下角为 ( x x , y y ) (xx,yy) (xx,yy) 的矩阵上,且结束点在左上(左下,右上,右下)角,形状为顺时针(逆时针)的最大路径价值和。

在这里插入图片描述
如图,以结束点在右上角为例,则可以转移到的图形有三种:
1. 1. 1. 可以由上一个结束点也在这个点的相同回环转移,如图1。
2. 2. 2. 可以由往下缩短一格后再加上此点的回环转移,如图2。
3. 3. 3. 可以由一个回环加上一段横行(竖行)转移,如图3。

所以要先用前缀和记录所有的横行和竖行的权值前缀和,以便 3 3 3 的转移。
并且图形是由小图形到大图形进行转移,所以要枚举这个回环的长和宽来进行 D P DP DP
转移的状态有 8 8 8 种,慢慢仔细打是可以打完的。

对与两个回环相接,可以得出结论:两个回环的方向相反。
之后枚举一个矩形的左上角和右下角,再分别枚举横,纵坐标的分割点,根据回环方向和回环的结束点更新答案就可以了。

D P DP DP 的时间复杂度为 O ( n 4 ) O(n^4) O(n4) ,枚举更新答案的时间复杂度为 O ( n 5 ) O(n ^ 5) O(n5) ,能过。

AC代码

#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
int n,m,a[40][40],ans=-21000000;
int f[40][40][40][40][4][2];
int hang[40][40],lie[40][40];
int Max(int a,int b,int c,int d)
{
	int tot=max(max(max(a,b),c),d);
	return tot;
}
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]);
	 	hang[i][j]=hang[i][j-1]+a[i][j];
	 	lie[i][j]=lie[i-1][j]+a[i][j];
	 	for(int k=0;k<=3;k++)
	 	 for(int l=0;l<=1;l++)
	 	 f[i][j][i][j][k][l]=a[i][j];
	 	ans=max(ans,a[i][j]);
	 }	
	for(int len1=1;len1<=n;len1++)//DP
	  for(int len2=1;len2<=m;len2++)
	  {
	  	if(len1==len2&&len1==1)
	  	continue;
	  	for(int x=1;x+len1-1<=n;x++)
	  	 for(int y=1;y+len2-1<=m;y++)
	  	 {
	  	 	 int xx=x+len1-1,yy=y+len2-1;
	  	     f[x][y][xx][yy][0][0]=Max(f[x][y][xx-1][yy][0][0],f[x][y+1][xx][yy][0][0],f[x+1][y][xx][yy][0][0]+a[x][yy],f[x][y][xx][yy-1][3][0]+lie[xx][yy]-lie[x-1][yy]);
			 f[x][y][xx][yy][1][0]=Max(f[x][y][xx-1][yy][1][0],f[x][y][xx][yy-1][1][0],f[x][y+1][xx][yy][1][0]+a[x][y],f[x+1][y][xx][yy][0][0]+hang[x][yy]-hang[x][y-1]);
			 f[x][y][xx][yy][2][0]=Max(f[x+1][y][xx][yy][2][0],f[x][y][xx][yy-1][2][0],f[x][y][xx-1][yy][2][0]+a[xx][y],f[x][y+1][xx][yy][1][0]+lie[xx][y]-lie[x-1][y]);
			 f[x][y][xx][yy][3][0]=Max(f[x+1][y][xx][yy][3][0],f[x][y+1][xx][yy][3][0],f[x][y][xx][yy-1][3][0]+a[xx][yy],f[x][y][xx-1][yy][2][0]+hang[xx][yy]-hang[xx][y-1]);
			 f[x][y][xx][yy][0][1]=Max(f[x][y][xx-1][yy][0][1],f[x][y+1][xx][yy][0][1],f[x][y][xx][yy-1][0][1]+a[x][yy],f[x+1][y][xx][yy][1][1]+hang[x][yy]-hang[x][y-1]);
			 f[x][y][xx][yy][1][1]=Max(f[x][y][xx-1][yy][1][1],f[x][y][xx][yy-1][1][1],f[x+1][y][xx][yy][1][1]+a[x][y],f[x][y+1][xx][yy][2][1]+lie[xx][y]-lie[x-1][y]);			
			 f[x][y][xx][yy][2][1]=Max(f[x+1][y][xx][yy][2][1],f[x][y][xx][yy-1][2][1],f[x][y+1][xx][yy][2][1]+a[xx][y],f[x][y][xx-1][yy][3][1]+hang[xx][yy]-hang[xx][y-1]);
			 f[x][y][xx][yy][3][1]=Max(f[x+1][y][xx][yy][3][1],f[x][y+1][xx][yy][3][1],f[x][y][xx-1][yy][3][1]+a[xx][yy],f[x][y][xx][yy-1][0][1]+lie[xx][yy]-lie[x-1][yy]);
		 }
	  }
	for(int len1=1;len1<=n;len1++)//枚举 
	 for(int len2=1;len2<=m;len2++)
	 {
	 	if(len1==len2&&len1==1)
	 	continue;
	 	for(int x=1;x+len1-1<=n;x++)
	 	 for(int y=1;y+len2-1<=m;y++)
	 	 {
	 	     int xx=x+len1-1,yy=y+len2-1;
	 	     for(int k=0;k<=3;k++)
	 	      for(int l=0;l<=1;l++)
	 	      ans=max(ans,f[x][y][xx][yy][k][l]);
			 for(int k=x;k<xx;k++)
			 {   
			   ans=max(ans,f[x][y][k][yy][2][0]+f[k+1][y][xx][yy][1][1]);
			   ans=max(ans,f[x][y][k][yy][3][1]+f[k+1][y][xx][yy][0][0]);
			 }	
			 for(int k=y;k<yy;k++)
			 {
			 	
			 	ans=max(ans,f[x][y][xx][k][3][0]+f[x][k+1][xx][yy][2][1]);
				ans=max(ans,f[x][y][xx][k][0][1]+f[x][k+1][xx][yy][1][0]);
			 }
		 }
	 }
	 printf("%d\n",ans);
}

http://www.niftyadmin.cn/n/1318762.html

相关文章

数据库设计注意要点

在一个项目开始初期&#xff0c;数据库的设计非常重要&#xff0c;很多时候&#xff0c;我们只关心和考虑到眼前的功能&#xff0c;而忽略了后续的可维护性和可拓展性&#xff0c;以及还有一个在大数据时代会遇到的高并发问题。  在设计表结构时要注意以下几个要点&#xff1…

九封信

有时候&#xff0c;莫名的心情不好&#xff0c;不想和任何人说话&#xff0c;只想一个人静静的发呆。有时候&#xff0c;想一个人躲起来脆弱&#xff0c;不愿别人看到自己的伤口。有时候&#xff0c;走过熟悉的街角&#xff0c;看到熟悉的背影&#xff0c;突然想起一个人的脸。…

【GDOI2014】采集资源 题解

题目大意 给出 nnn 种苦工&#xff0c;每一种苦工有 AiA_{i}Ai​ 和 BiB_{i}Bi​ &#xff0c;表示每一个 iii 种苦工单位时间内可以获取 AiA_{i}Ai​ 点资源&#xff0c;而招募一个消耗的资源为 BiB_{i}Bi​ 点&#xff0c;给出初始资源 mmm 和目标资源 TTT 求最少的单位时间…

【GDOI2013】字母连接 题解

题面 有一个游戏&#xff0c;在平面上给定m行n列的格子。在部分格子上存在障碍物&#xff0c;在没有障碍物的格子上可能有英文字母。现在要求在空格子上建立路径&#xff0c;使得每条路径两端分别有一个字母&#xff0c;且两端的字母互不相同&#xff0c;并且所有字母都通过路…

Java中List与Map初始化的一些写法

Java的在还没有发现新写法之前时&#xff0c;我一直是这么初始化List跟Map&#xff1a; //初始化List List list new ArrayList(); list.add("string1"); list.add("string2"); //some other list.add() code...... list.add("stringN"); //初始…

二叉树系列四:二叉树的遍历(非递归)

在二叉树系列三中讲述了二叉树的前序遍历、中序遍历和后序遍历的递归实现&#xff0c;可以看到采用递归实现的代码非常简单&#xff0c;但是代码简单不代表实际运行过程中也能达到最简。下面将要介绍二叉树几种遍历的非递归实现实现。 &#xff08;1&#xff09;前序遍历 1 te…

GDOI2022普及组总结

Day -5 本来是可以去打提高组&#xff08;真正的省选&#xff09;的&#xff0c;但是由于疫情太严重&#xff0c;于是初中生被大量裁剪&#xff0c;要 NOIPNOIPNOIP 前 505050 才可以进&#xff08;和高中生一起排&#xff0c;难度不亚于省选&#xff09;&#xff0c;我太弱了…