【SSL】1209旅行(normal)

SSL_MYD發表於2020-12-10

【SSL】1209旅行(normal)

Time Limit:1000MS
Memory Limit:65536K

Description

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

Input

輸入有m+1行,第一行有兩個整數m,n(m,n定義如上)。其中( ),接下來的m行,每行n個整數,第i行第j個數表示分數V(i,j)。(-128<=v(i,j)<=127)每兩個整數之間有一個空格。

Output

輸入只一行,分兩種情況:
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
Sample Output
樣例1
146
樣例2
NO

思路

這道題就是求最大子矩陣和。其實是用最大連續數列的和來做。雙重迴圈列舉行,再把範圍內的每一列數求和,計算最大連續數列的和,與最大值比較。
求最大連續數列的和:
設f[i]存前i個數的最長連續數列和.
狀態轉移方程:
當a[i]+f[i-1]<0,f[i]=0
當a[i]+f[i-1]<0,f[i]=a[i]+f[i-1]
如果結果<=0,輸出”NO”,否則輸出結果。

程式碼

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<iomanip>
#include<cstdlib>
#include<algorithm>
using namespace std;
int n,m,a[1010][1010],b[1010],c[1010];
void input()
{
	int i,j;
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;i++)
	{
		for(j=1;j<=m;j++)
		{
			scanf("%d",&a[i][j]);
		}
	}
	return;
}
int DP()
{
	int i,ans=0;
	for(i=1;i<=m;i++)
	{
		c[i]=b[i]+c[i-1];
		if (c[i]<0)
			c[i]=0;
		ans=max(ans,c[i]);
	}
	return ans;
}
void work()
{
	int i,j,k,ans=0;
	for(i=1;i<=n;i++)
	{
		memset(b,0,sizeof(b));
		for(j=i;j<=n;j++)
		{
			for(k=1;k<=m;k++)
				b[k]+=a[j][k];
			ans=max(ans,DP());
		}
	}
	if (ans<=0)
		printf("NO");
	else
		printf("%d",ans);
	return;
}
int main()
{
	input();
	work();
	return 0;
} 

相關文章