【SSL_1209】 旅行

旅行

题目

ACM队员们到Z镇游玩,Z镇是一个很特别的城镇,它有m+1条东西方向和n+1条南北方向的道路,划分成MN个区域。Z镇的名胜位于这些区域内,从上往下第i行,从左往右数第j列的区域记为D(i,j)。ACM队员们预先对这MN个区域打分V(i,j)(分数可正可负)。分数越高表示他们越想到那个地方,越低表示他们越不想去。为了方便集合,队员们只能在某一个范围内活动。我们可以用(m1,n1)与(m2,n2)(m1<=m2,n1<=n2)表示这样一个范围:它是这些区域的集合:ACM队员希望他们活动区域的分值总和最大。
当然,有的队员可能一个也不去(例如,所有区域的分值都是负数。当然,如果某范围内的分值和为0的话,他们也不会去玩)。也有可能他们游览整个Z镇。你的任务是编写一个程序,求出他们的活动范围(m1,n1),(m2,n2)。

输入

输入有m+1行,第一行有两个整数m,n(m,n定义如上)。其中( ),接下来的m行,每行n个整数,第i行第j个数表示分数V(i,j)。(-128<=v(i,j)<=127)每两个整数之间有一个空格。

输出

输入只一行,分两种情况:
1. 队员在范围内(m1,n2)(m2,n2)内活动,输出该范围内的分值。
2. 队员们任何地方都不去,只需输出NO。
注意:不要输出多余的空行,行首行尾不要有多余的空格。

Sample Input

样例1

4 5
1 -2 3 -4 5
6 7 8 9 10
-11 12 13 14 -15
16 17 18 19 20

样例2

2 3
-1 -2 -1
-4 -3 -6
1
2

Sample Output

样例1

146

样例2

NO

思路

这题求的是最大前缀和矩阵。
输入后将第一行和第一列预处理一下,及求前缀和。
预处理前:

1 2 3 1
1 1 1 2
2 1 1 1

预处理后:

1 3 6 7
2 1 1 2
4 1 1 1

f [ i ] [ j ] 表 示 从 f [ 1 ] [ 1 ] 到 f [ i ] [ j ] 的 和 f[i][j]表示从f[1][1]到f[i][j]的和 f[i][j]f[1][1]f[i][j]
即 矩 阵 ( 1 , 1 ) , ( i , j ) 的 总 和 即矩阵(1,1),(i,j)的总和 (1,1),(i,j)
状态转移方程:
f [ i ] [ j ] + = f [ i − 1 ] [ j ] + f [ i ] [ j − 1 ] − f [ i − 1 ] [ j − 1 ] f[i][j]+=f[i-1][j]+f[i][j-1]-f[i-1][j-1] f[i][j]+=f[i1][j]+f[i][j1]f[i1][j1]
1 < = i < = n , 1 < = j < = m 1<=i<=n,1<=j<=m 1<=i<=n,1<=j<=m
意思是矩阵(1,1)到(i-1,j)加矩阵(1,1)到(i,j-1),
再减去它们重叠的部分即矩阵(1,1)到(i-1,j-1),
再加上它本身的权值就为矩阵(1,1)到(i,j)的总值了。
全部处理后上图矩阵变为:

1 3 6 7
2 5 9 12
4 8 13 17

程序

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<cstdlib>
using namespace std;
int n,m,f[10001][10001],ans,d;
void in(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			scanf("%d",&f[i][j]);
			if(f[i][j]>0){
				d=1;
			}
		}
	}if(d==0){//若无正数直接say no!
		printf("NO");
		exit(0);
	}//下面是预处理第一行与第一列
	for(int i=2;i<=n;i++){
		f[i][1]+=f[i-1][1];
	}for(int j=2;j<=m;j++){
		f[1][j]+=f[1][j-1];
	}
}void DP(){
	for(int i=2;i<=n;i++){
		for(int j=2;j<=m;j++){
			f[i][j]+=f[i][j-1]+f[i-1][j]-f[i-1][j-1];//求前缀和矩阵
			ans=max(f[i][j],ans);//记录最佳答案
		}
	}
}
int main(){
	in();
	DP(); 
	if(ans==0){
		printf("NO");
	}else
	printf("%d",ans);
} 
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值