【洛谷】P1004 方格取数

题目链接

题目描述

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

 0  0  0  0  0  0  0  0
 0  0 13  0  0  6  0  0
 0  0  0  0  7  0  0  0
 0  0  0 14  0  0  0  0
 0 21  0  0  0  4  0  0
 0  0 15  0  0  0  0  0
 0 14  0  0  0  0  0  0
 0  0  0  0  0  0  0  0

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

输入输出格式

输入格式:

 

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

 

输出格式:

 

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

 

输入输出样例

输入样例#1: 复制

8
2 3 13
2 6  6
3 5  7
4 4 14
5 2 21
5 6  4
6 3 15
7 2 14
0 0  0

输出样例#1: 复制

67

 

一开始想当然的认为2 条路径上取得的最大的和等于第一次路径最大和加上取点后第二次路径最大和,结果WA了,只有80分。错的那个测试点是:

7

1 3 2

1 4 3

2 3 3

3 3 3

5 5 4

6 5 4

7 3 2

7 5 4

0 0 0

程序输出是23,而正确答案是25。错的原因是23=20(第一次最大值)+3(第二次最大值),25=19(并不是第一次最大值)+5(第二次最大值)。也就是说一开始的想法错了。

先附上80分代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<iomanip>
#include<vector>
#include<stack>
using namespace std;
int Map[10][10];//方格上的数 
int dp[10][10];//dp[i][j]表示从Map[1][1]到Map[i][j]的最大路径和 
bool path[10][10];//要取出数的方格置为1 
int N;
bool flag=0;
void recur() 
{
	memset(dp,0,sizeof(dp));
	dp[1][1]=Map[1][1];
	for(int j=2;j<=N;j++)
	    dp[1][j]=dp[1][j-1]+Map[1][j];
	for(int i=2;i<=N;i++)
	    dp[i][1]=dp[i-1][1]+Map[i][1];
	for(int i=2;i<=N;i++)
	    for(int j=2;j<=N;j++)
		    dp[i][j]=max(dp[i-1][j],dp[i][j-1])+Map[i][j];
}
int sum;
void anti_recur(int i,int j)
{
	if(i==1&&j==1) 
	{   
	    if(sum==Map[1][1])flag=1;
	    path[i][j]=1;
		return;
	}
	if(sum==Map[i][j]+dp[i][j-1]) 
	{  
		path[i][j]=1;sum-=Map[i][j];
		anti_recur(i,--j);
		if(flag) return;
		path[i][j]=0;sum+=Map[i][j];
	}
	else if(sum==Map[i][j]+dp[i-1][j])
	{  
		path[i][j]=1;sum-=Map[i][j];
		anti_recur(--i,j);
		if(flag) return;
		path[i][j]=0;sum+=Map[i][j];
        }
}
int main()
{
	int x,y,num,ans=0;
	cin>>N;
	memset(Map,0,sizeof(Map));
	while(cin>>x>>y>>num,x!=0&&y!=0&&num!=0)
	{Map[x][y]=num;}
	recur();//第一次求出最大路径和为dp[N][N] 
	ans+=dp[N][N];
	
	memset(path,0,sizeof(path));
	sum=dp[N][N];
	anti_recur(N,N);//将要取出数的方格求出来 
	
	for(int i=1;i<=N;i++)
	    for(int j=1;j<=N;j++)
		    if(path[i][j]&&Map[i][j])  Map[i][j]=0;//取走第一次经过方格的数 
	
	recur();//递推,第二次求出最大路径和为dp[N][N] 
	ans+=dp[N][N];
	
	cout<<ans;
}

后开看了下题解,了解到这题是四维动规的模板题(生无可恋.jpg)用dp[i][j][k][l]表示两个人分别从Map[1][1]走到Map[i][j]和Map[k][l]的最大路径和,显然,这题最后的结果是dp[N][N][N][N],注意的是如果两个人走到相同格子,则最大路径和要减去相同格子里面的数,因为其被计算了两遍。

AC代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<iomanip>
#include<vector>
#include<stack>
using namespace std;
int N;
int Map[10][10];
int dp[10][10][10][10];
int main()
{
	int  x,y,num;
	cin>>N;
	memset(Map,0,sizeof(Map));
	memset(dp,0,sizeof(dp));
	while(cin>>x>>y>>num,x!=0&&y!=0&&num!=0)
	{Map[x][y]=num;}
	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++)
				{
					dp[i][j][k][l]=max(
					max(dp[i-1][j][k-1][l],dp[i-1][j][k][l-1]),
					max(dp[i][j-1][k-1][l],dp[i][j-1][k][l-1]))
					+Map[i][j]+Map[k][l];
					if(i==k&&j==l) dp[i][j][k][l]-=Map[i][j];
				}
			}
		}
	}
	cout<<dp[N][N][N][N];	
}

空间复杂度还可以优化。洛谷是真的强,题解很全,错误样例也可以下载(๑╹◡╹)ノ"""

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值