[NOIP2000 提高组] 方格取数 题解

目录

前言

题面

题目描述

输入格式

输出格式

解法

代码


前言

更好的阅读环境:link

题面

你可以在这里阅读:link

也可以看下文阅读题面。

题目描述

设有 N×N 的方格图 (N≤9),我们将其中的某些方格中填入正整数,而其他的方格中则放入数字 0。如下图所示(见样例):

某人从图的左上角的 A 点出发,可以向下行走,也可以向右走,直到到达右下角的 B 点。在走过的路上,他可以取走方格中的数(取走后的方格中将变为数字 0)。
此人从 A 点到 B 点共走两次,试找出 2 条这样的路径,使得取得的数之和为最大。

输入格式

输入的第一行为一个整数 N(表示 N×N 的方格图),接下来的每行有三个整数,前两个表示位置,第三个数为该位置上所放的数。一行单独的 0 表示输入结束。

输出格式

只需输出一个整数,表示 2 条路径上取得的最大的和。

解法

考虑使用三维动态规划,使用最基础的动态规划跑两遍明显过不了。首先我们要解决一个问题:如何避免一个格子被拿两遍?我们可以同时遍历两个路径。我们设第一条路径目前的横坐标为 i,纵坐标为 j。再设第二条路径目前的横坐标为 k,纵坐标为 l。不难发现 i+j 一定等于 k+l。因为他们的坐标总和只能在每一步中加一,而这两个坐标又是同时移动的。这样就需要四个维度。我们可以进行降维优化。接下来我要重新定义一些上文定义过的变量,请勿参考上文的变量来理解下文的变量。我们可以设 i 为我们现在总共走的步数,设 j 为第一条路径目前的横坐标,再设 k 为第二条路径目前的横坐标。我们可以设一个三维数组 dp 用来存储相应的状态,进行状态转移。状态转移方程十分好推,这里就不给出了,如果真的不知道状态转移方程是什么,就去看我的代码,我的代码中间有个三重循环,这个三重循环里面就是状态转移方程的实现部分。最终答案为 dp_{n \times 2,n,n}​。

代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,dp[110][110][110],mp[1100][1100];
signed main(){
	ios::sync_with_stdio(false);
	cin>>n;
	while(true){
		int x,y,num;
		cin>>x>>y>>num;
		if(x==0&&y==0&&num==0){
			break;
		}else{
			mp[x][y]=num;
		}
	}
	for(int i=2;i<=n*2;i++){
		for(int j=max(i-n,1ll);j<=min(n,i-1);j++){
			for(int k=max(i-n,1ll);k<=min(n,i-1);k++){
				dp[i][j][k]=max(max(max(dp[i-1][j][k],dp[i-1][j-1][k-1]),dp[i-1][j][k-1]),dp[i-1][j-1][k]);
				dp[i][j][k]+=mp[j][i-j];
				if(j!=k){
					dp[i][j][k]+=mp[k][i-k];
				}
			}
		}
	}
	cout<<dp[n*2][n][n];
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值