首页 > 其他分享 >P1004 NOIP2000 提高组 方格取数

P1004 NOIP2000 提高组 方格取数

时间:2024-10-29 10:32:24浏览次数:4  
标签:x1 NOIP2000 int P1004 取数 x2 maxn y1 y2

P1004 NOIP2000 提高组 方格取数 - 洛谷

分析

与 [[小烈送菜]] 算姐妹题了,这个辈分甚至更老一点。

如果直接按照题目,从 \(A, B\) 两点分别出发,那么有个问题就是不确定性,计算的时候不可控因素很多。

可以注意到,从 \(B\) 点往回走到 \(A\) 点,是和从 \(A\) 点再走一遍走到 \(B\) 点是等价的。
那么这道题就可以转化为两个人从 \(A\) 点同时出发,路径可以交叉,求从方格中取数的最大总和。

接下来,分类讨论一下可能的情况。假设当前第一个人在 \((x1, y1)\),第二个人在 \((x2, y2)\),那么在下一步,会有以下四种情况:

  1. 同时向下走。
  2. 同时向右走。
  3. 第一个向下走,第二个向右走。
  4. 第一个向右走,第二个向下走。

同理,第一个人在 \((x1, y1)\),第二个人在 \((x2, y2)\) 的情况,也可以由以下四个位置到达:

  1. \((x1 - 1, y1), (x2 - 1, y2)\)
  2. \((x1, y1 - 1),(x2, y2 - 1)\)
  3. \((x1 - 1, y1),(x2, y2 - 1)\)
  4. \((x1, y1 - 1),(x2 - 1, y2)\)

分析到这个地方,这题已经很好做了。根据上面的第一种讨论,可以写出一个记忆化搜索;而根据第二种讨论,很容易写出一种四维 DP。

另外,根据题意,同一个方格最多只能取一次,所以要判断坐标重叠的情况。

代码

DP 写法

#include <bits/stdc++.h>
using namespace std;

const int maxn = 10;
int n;
int graph[maxn][maxn];
int f[maxn][maxn][maxn][maxn];

int main() {
	scanf("%d", &n);
	while (true) {
		int x, y, val;
		scanf("%d%d%d", &x, &y, &val);
		if (x == 0 && y == 0 && val == 0) break;
		graph[x][y] = val;
	}
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= n; j++) {
			for (int k = 1; k <= n; k++) {
				for (int l = 1; l <= n; l++) {
					f[i][j][k][l] = max(f[i][j][k][l], f[i - 1][j][k - 1][l] + graph[i][j] + graph[k][l] * (i != k || j != l)); // 坐标判重,相同坐标只计算一次。
					f[i][j][k][l] = max(f[i][j][k][l], f[i][j - 1][k][l - 1] + graph[i][j] + graph[k][l] * (i != k || j != l));
					f[i][j][k][l] = max(f[i][j][k][l], f[i - 1][j][k][l - 1] + graph[i][j] + graph[k][l] * (i != k || j != l));
					f[i][j][k][l] = max(f[i][j][k][l], f[i][j - 1][k - 1][l] + graph[i][j] + graph[k][l] * (i != k || j != l));
				}
			}
		}
	}
	printf("%d", f[n][n][n][n]);
	return 0;
}

记忆化搜索

#include <bits/stdc++.h>
using namespace std;

const int maxn = 10;
int n;
int f[maxn][maxn][maxn][maxn];
int val[maxn][maxn];

inline bool inArea(int x, int y) {
	return x >= 1 && x <= n && y >= 1 && y <= n;
}

int dx1[4] = {1, 0, 1, 0};
int dy1[4] = {0, 1, 0, 1};
int dx2[4] = {1, 0, 0, 1};
int dy2[4] = {0, 1, 1, 0};
int dfs(int _x1, int _y1, int _x2, int _y2) {
	if (f[_x1][_y1][_x2][_y2] != -1) return f[_x1][_y1][_x2][_y2];
	if (_x1 == n && _y1 == n && _x2 == n && _y2 == n) return 0;
	int maxv = -1;
	for (int i = 0; i < 4; i++) {
		int vx1 = _x1 + dx1[i], vy1 = _y1 + dy1[i];
		int vx2 = _x2 + dx2[i], vy2 = _y2 + dy2[i];
		if (!inArea(vx1, vy1) || !inArea(vx2, vy2)) continue;
		maxv = max(maxv, dfs(vx1, vy1, vx2, vy2) + val[vx1][vy1] + val[vx2][vy2] * (vx1 != vx2 || vy1 != vy2));
	}
	f[_x1][_y1][_x2][_y2] = maxv;
	return f[_x1][_y1][_x2][_y2];
}

int main() {
	scanf("%d", &n);
	memset(f, -1, sizeof(f)); // 注意初始化为 -1, 因为可能出现取的数为 0 的情况
	while (true) {
		int x, y, v;
		scanf("%d%d%d", &x, &y, &v);
		if (x == 0 && y == 0 && v == 0) break;
		val[x][y] = v;
	}
	dfs(1, 1, 1, 1);
	printf("%d", f[1][1][1][1] + val[1][1]); // 搜索时没有算 (1, 1),在这里加上
	return 0;
}

标签:x1,NOIP2000,int,P1004,取数,x2,maxn,y1,y2
From: https://www.cnblogs.com/jxyanglinus/p/18512427

相关文章

  • Redis 厨神:用 StringRedisTemplate 轻松获取数据的秘笈
    前言在这个快节奏的时代,数据处理就像烹饪,既需要精准的配料,又需要高超的烹饪技巧。想象一下,你在厨房里忙得不可开交,却被突如其来的订单搞得手忙脚乱。今天,我们要揭开如何用StringRedisTemplate轻松获取数据的秘密,让你在SpringBoot3.x的世界里,摇身一变,成为Redis的厨房大......
  • P7074 [CSP-J2020] 方格取数 题解
    动态规划dp方格取数类似于数字三角形,均可以使用动态规划直接秒杀.但此题有$3$个方向:上、右、下.所以可以定义一个三维数组dp数组.假设$f_{i,j,1}$是从右、上方到达$(i,j)$的和的最大值.又有$f_{i,j,0}$是从右、下方到达$(i,j)$的和的最大值.我们可以先确定......
  • PbootCMS打开后提示读取数据库文件失败: Unable to open database
    问题表现打开PbootCMS时提示“读取数据库文件失败:Unabletoopendatabase”。原因数据库文件没有读写权限。解决方法设置文件夹权限:将 data 文件夹设置为777权限。同时将 config、static、runtime、data 文件夹设置为可读写权限。注意事项备份文件......
  • JSONPath,一个事半功倍的查找取数工具
    目录前言JSONPath介绍操作项筛选器运算符函数样本使用说明延伸前言日常在书写用例断言的时候,经常会遇到这样的场景:从结果中提取关键属性用于后续业务或者断言。一般遇到这类情况,处理方式基本都跟剥洋葱一样,遇到数组/集合,一层层循环读取,遇到对象套对象,一层层对象点......
  • P1004 [NOIP2000 提高组] 方格取数
    要走两次因此,考虑一个四维的数组来实现,然后如果i=k&&j==l的话记得减一次即得到答案。点击查看代码#include<iostream>#include<stack>#include<cmath>#include<algorithm>#include<set>#include<vector>#include<climits>#include<string.h&g......
  • Python爬虫:获取数据的入门详解
    在互联网时代,数据已成为最宝贵的资源之一。Python,作为一种功能强大且易于学习的编程语言,成为了数据获取和处理的理想工具。Python爬虫,特别是,允许我们从网页中自动提取大量数据,为数据分析、机器学习、研究和开发等多种应用提供了原材料。本文将为您提供一个Python爬虫的入门详解......
  • <<迷雾>> 第11章 全自动加法计算机(6)--一只开关取数 示例电路
    用一只开关依次将数取出info::操作说明刚启动时,t0=1,t1=t2=0,此时只有IAR`=1.按下开关K不要松开,地址寄存器AR收到一个上升沿信号,保存住当前地址,并提供给存储器(注:第一个地址为0,所以电路中暂看不出什么变化)松开开关K,循环移位计数器RR得到......
  • datatables使用ajax获取数据
    前端://初始化datatablevartable3=$('.jiaoshi_lst').DataTable({"processing":true,"serverSide":true,"paging":true,"ordering":false,"searching":false......
  • Pandas DataFrame对象df 读取数据
    你的df是一个PandasDataFrame对象,类似于一个表格结构的数据,通常有行和列。根据你的描述,表格中有多列数据,例如TS_CODE,DATE,TIME,OPEN等,总共有33列。要显示df中某个特定项目的值,例如“股票的当前价格”,你可以按照以下方式来操作。假设df里有一列CURRENT_PRICE表......
  • 信息学奥赛复赛复习11-CSP-J2020-04方格取数-动态规划、斐波那契数列、最优子结构、重
    PDF文档公众号回复关键字:202410041P7074[CSP-J2020]方格取数[题目描述]设有n×m的方格图,每个方格中都有一个整数。现有一只小熊,想从图的左上角走到右下角,每一步只能向上、向下或向右走一格,并且不能重复经过已经走过的方格,也不能走出边界。小熊会取走所有经过的方格中......