[洛谷]P2380 狗哥采矿 (#线性dp)

题目背景

又是一节平静的语文课

狗哥闲来无事,出来了这么一道题

题目描述

一个n*m的矩阵中,每个格子内有两种矿yeyenum和bloggium,并且知道它们在每个格子内的数量是多少。最北边有bloggium的收集站,最西边有 yeyenum 的收集站。现在要你在这些格子上面安装向北或者向西的传送带(每个格子只能装一种)。问最多能采到多少矿?

输入格式

第一行包含两个整数n,m,( 1 ≤ n ≤ 500, 1 ≤ m ≤ 500)。接下来n行m列,表示每个格子中可以传送到yeyenum的数量(小于1000),再接下来n行m列,表示每个格子中可以传送到bloggium的数量。n, m 同时为0结束。

输出格式

每组测试数据仅输出一个数,表示最多能采到的矿。

输入输出样例

输入 #1复制

4 4
0 0 10 9 
1 3 10 0
4 2 1 3 
1 1 20 0 
10 0 0 0 
1 1 1 30 
0 0 5 5 
5 10 10 10 
0 0

输出 #1复制

98

说明/提示

传输过程中不能转弯,只能走直路。


思路

令dp[i][j]为以点(i,j)为右下角时的矩阵中最大采矿量。由于传送带不能转弯,所以在点(i,j)上,向左就会一直向左,向上就会一直向上。所以点(i,j)如果向左挖矿,可以从点(i,j-1)转移过来,而(i,j-1)也可以从点(i,j-2)转移过来,一直到(i,1)。同理,点(i,j)如果向上挖矿,可以从点(i-1,j)转移过来,而(i-1,j)也可以从点(i-2,j)转移过来,一直到(1,j)。

在挖矿的过程中,能影响dp[i][j]的值只有挖矿方向。用a[i][j]来记录向上的矿的前缀和,用b[i][j]来记录向左的矿的前缀和。则:

dp[i][j]=max(dp[i][j-1]+a[i][j],dp[i-1][j]+b[i][j])

答案为dp[n][m]。

#include <stdio.h>
#include <iostream>
#include <memory.h>
#define maxn 501
using namespace std;
int n,m,a[maxn][maxn],b[maxn][maxn],dp[maxn][maxn],inf;
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	register int i,j,k,x,y;
	cin>>n>>m;
	while(n!=0 && m!=0)
	{
		memset(dp,0,sizeof(dp));
		for(i=1;i<=n;i++)
		{
			for(j=1;j<=m;j++)
			{
				cin>>a[i][j];
				a[i][j]+=a[i][j-1];
			}
		}
		for(i=1;i<=n;i++)
		{
			for(j=1;j<=m;j++)
			{
				cin>>b[i][j];
				b[i][j]+=b[i-1][j];
			}
		}
		for(i=1;i<=n;i++)
		{
			for(j=1;j<=m;j++)
			{
				dp[i][j]=max(dp[i-1][j]+a[i][j],dp[i][j-1]+b[i][j]);
			}
		}
		cout<<dp[n][m]<<endl;
		cin>>n>>m;
	}
	return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值