1. 程式人生 > >P2380 狗哥採礦【題解】

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])

還有:注意是多組資料
程式碼:
#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;
}