/*
吐槽:
唔。。。从早上就开始看这个题了- -又荒废了一天。
早上睡觉到十点半,然后就开了个会到12点,回来睡觉到4点多起来看B站,看楼教主的回忆录,跟看小说似的
到晚上才开始编
又是自己想了想觉得暴力不行就去搜代码了
- -不解释了
*/
题意:
求一个N*N的矩阵的最大子矩阵
思路:
把二维压缩成一维,转化为求一维数组的最大子序列(表示连一维的也木有做过,)但是此题只需求最大子矩阵的和值就行了,不需要知道位置,所以一维的dp甚至可以转化为0维!
下面是在别人博客里面找到的一维求最长子序列的方法:
(转载于http://blog.youkuaiyun.com/nomad2/article/details/6443620)
1、首先考虑一维的最大子段和问题,给出一个序列a[0],a[1],a[2]...a[n],求出连续的一段,使其总和最大。
a[i]表示第i个元素
dp[i]表示以a[i]结尾的最大子段和
dp[i] = max{a[i], dp[i-1] + a[i]}
解释一下方程:
如果dp[i-1] > 0,则 dp[i] = dp[i-1] + a[i]
如果dp[i-1] < 0,则 dp[i] = a[i]
因为不用记录位置信息,所以dp[]可以用一个变量dp代替:
如果dp > 0,则dp += a[i]
如果dp < 0,则dp = a[i]
二维转一维就可以暴力了,这里把第i行到第i+k行的数相加得到一维数组
原题:
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 36381 | Accepted: 19108 |
Description
As an example, the maximal sub-rectangle of the array:
0 -2 -7 0
9 2 -6 2
-4 1 -4 1
-1 8 0 -2
is in the lower left corner:
9 2
-4 1
-1 8
and has a sum of 15.
Input
Output
Sample Input
4 0 -2 -7 0 9 2 -6 2 -4 1 -4 1 -1 8 0 -2
Sample Output
15
Run ID | User | Problem | Result | Memory | Time | Language | Code Length | Submit Time |
11765976 | chengtbf | 1050 | Accepted | 208K | 16MS | C++ | 1002B | 2013-07-11 20:17:29 |
代码:
#include<stdio.h>
#include<string.h>
#define INF -10000000
#define N 105
int a[N][N],str[N],dp;//dp甚至可以降维到一个变量
int ans,n;
int find_max(int a,int b)
{
if (a>b)
{
return a;
}
else
{
return b;
}
}
void find_ans()//一维的求最长子序列
{
int i;
dp=0;//初始化dp,涵义是以i为结束的最长子串
for ( i = 1; i <=n; i++)
{
dp=find_max(str[i],dp+str[i]);
ans=find_max(dp,ans);
}
}
int main()
{
int i,j,i_start,i_end;
while (scanf("%d",&n)!=EOF)
{
memset(a,0,sizeof(a));
for ( i =1; i <=n ; i++)
{
for ( j= 1; j<=n; j++)
{
scanf("%d",&a[i][j]);
if(i>=2)
{
a[i][j]+=a[i-1][j];//a[i][j]表示当前第j列前i行的和a[1][j]+a[2][j]+....+a[i][j]
}
}
}
ans=a[1][1];//初始化结果
for ( i_start = 1; i_start <=n ; i_start++)
{
for ( i_end = i_start; i_end <=n ; i_end++)
{
for ( j = 1; j <=n ; j++)
{
str[j]=a[i_end][j]-a[i_start][j];//初始化一维数组
}
find_ans();
}
}
printf("%d\n",ans);
}
return 0;
}