P2380 狗哥采矿【题解】

题目背景

又是一节平静的语文课

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

题目描述

一个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

说明

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


f [ i ] [ j ] f[i][j] ( 1 , 1 ) (1,1) ( i , j ) (i,j) 的子矩阵中的最大采矿量,由题意我们可知,如果点 ( i , j ) (i,j) 的传送带向左,那么点 ( i , j 1 ) (i,j-1) 及其左边一定是向左,同理,如果 ( i , j ) (i,j) 的传送带向上,那么点 ( i 1 , j ) (i−1,j) 及其上边的点,一定也是向上。

于是我们可以用前缀和去维护一段区间的采矿量。

在转移时,我们只考虑 ( i , j ) (i,j) 的两种方向。设 H H 为向左的前缀和, S [ i ] [ j ] S[i][j] 为向上的前缀和,那么转移方程 f [ i ] [ j ] = m a x ( f [ i 1 ] [ j ] + H [ i ] [ j ] , f [ [ i ] [ j 1 ] + S [ i ] [ j ] ) f[i][j]=max(f[i-1][j]+H[i][j],f[[i][j-1]+S[i][j])

扫描二维码关注公众号,回复: 4509097 查看本文章
还有:注意是多组数据
代码:
#include<iostream>
#include<cstdio>
#include<ctype.h>
using namespace std;
inline int read(){
	int x=0,f=0;char ch=getchar();
	while(!isdigit(ch))f|=ch=='-',ch=getchar();
	while(isdigit(ch))x=x*10+(ch^48),ch=getchar();
	return f?-x:x;
}
struct OOO{
	int S,H;
}a[507][507];
int f[507][507];
int main(){
	int n=read(),m=read();
	while(n && m){
		for(int i=1;i<=n;++i)for(int j=1;j<=m;++j){
			a[i][j].H=read();a[i][j].H+=a[i][j-1].H;
		}
		for(int i=1;i<=n;++i)for(int j=1;j<=m;++j){
			a[i][j].S=read();a[i][j].S+=a[i-1][j].S;
		}
		for(int i=1;i<=n;++i){
			for(int j=1;j<=m;++j){
				f[i][j]=max(f[i-1][j]+a[i][j].H,f[i][j-1]+a[i][j].S);
			}
		}
		printf("%d\n",f[n][m]);
		n=read(),m=read();
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_44023181/article/details/84955969