POJ1050 To the Max
假设最大子矩阵的结果为从第r行到k行、从第i列到j列的子矩阵,
如下所示(ari表示a[r][i]
,假设数组下标从1开始):
| a11 …… a1i ……a1j ……a1n |
| a21 …… a2i ……a2j ……a2n |
| . . . . |
| . . . . |
| ar1 …… ari ……arj ……arn |
| . . . . |
| . . . . |
| ak1 …… aki ……akj ……akn |
| . . . . |
| an1 …… ani ……anj ……ann |
将从第r行到第k行的每一行中相同列的加起来,可以得到一个一维数组如下:
(ar1+……+ak1, ar2+……+ak2, ……,arn+……+akn)
由此看出最后所求的就是此一维数组的最大子段和问题
将最大子矩阵问题分解为最大子段和,时间复杂度O(n^3)。
#include <stdio.h>
#include <string.h>
#define INF 0x3f3f3f3f
using namespace std;
int main()
{
int n;
while(scanf("%d",&n)!=EOF){
int m[n][n];
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
scanf("%d",&m[i][j]);
}
}
// for(int i=0;i<n;i++){
// for(int j=0;j<n;j++){
// printf("%d ",m[i][j]);
// }
// printf("\n");
// }
// printf("\n");
int a[n][n];
memset(a,0,sizeof(a));
//a[i][j]保存第i列从第0行到第j行的和
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
for(int t=0;t<=j;t++){
a[i][j]+=m[t][i];
}
}
}
// for(int i=0;i<n;i++){
// for(int j=0;j<n;j++){
// printf("%d ",a[i][j]);
// }
// printf("\n");
// }
int sum=-INF;
// int rBegin=0,rEnd=0;
// int cBegin=0,cEnd=0;
for(int i=0;i<n;i++){
for(int j=i;j<n;j++){
int tem=0;
//cBegin=0,cEnd=0;
for(int k=0;k<n;k++){
int aij=0;
if(i==0){
aij=a[k][j];
}else{
aij=a[k][j]-a[k][i-1];
}
//a[k][j]-a[k][i-1]表示第k列从第i行到第j行的和
if(tem>=0)tem+=aij;
else{
tem=aij;
//cBegin=k;
}
if(tem>sum){
sum=tem;
//rBegin=i,rEnd=j;
//cEnd=k;
}
}
}
}
// printf("%d %d %d %d \n",rBegin,rEnd,cBegin,cEnd);
// for(int i=rBegin;i<=rEnd;i++){
// for(int j=cBegin;j<=cEnd;j++){
// printf("%d ",m[i][j]);
// }
// printf("\n");
// }
printf("%d\n",sum);
}
return 0;
}
//测试用例
4
0 -2 -7 0
9 2 -6 2
-4 1 -4 1
-1 8 0 -2
15
补充
C函数之memset()函数用法:
1.功能:将s所指向的某一块内存中的每个字节的内容全部设置为ch指定的ASCII值, 块的大小由第三个参数指定,这个函数通常为新申请的内存做初始化工作, 其返回值为指向S的指针
2. 需要的头文件 <memory.h> or <string.h>
3.函数原型:void *memset(void *s,int ch, unsigned n)
4.memset可以方便的清空一个结构类型的变量或数组(在程序设计中的主要用法)