原题传送门:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=44
题目大意:给出一个N*N的矩阵,求出元素和最大的矩阵,输出其元素和
思路:第一想法。。。依旧是暴力。。然而o(n^4)会不会有点夸张。。。哪怕数据只有100也能达到1E。。明显不行,换方法。。。然后就YY出了点东西,暴力解的时候,每次去求一个矩阵的时候都必须把每个元素加一遍,像s[j][k]+s[j][k+1]+…s[j][l],其实可以预处理使map[j][k]为s[j][1]+s[j][2]+…s[j][k],那么之前那个也就可以一步map[j][l]-map[j][l-1],现在再来暴力枚举,就只需要枚举矩阵的左右界就行了,右界减左界就是中间的数的和,那么纵向就变成了一个一维的序列,然后贪心或者dp求一下就行了(具体的参考UVA10684 http://blog.youkuaiyun.com/silence__bug/article/details/46889363,时间复杂度为o(n)),那么总时间复杂度就是o(n^3),下降了一次幂
处理样例:
0 -2 -7 0
9 2 -6 2
-4 1 -4 1
-1 8 0 -2
转化为
0 -2 -9 -9
9 11 5 7
-4 -3 -7 -6
-1 7 7 5
枚举到左右界为1-2时,纵向就变成了一维序列:-2,11,-3,7
枚举到左右界为1-3时,纵向就变成了一维序列:-9,5,-7,7
枚举到左右界为2-3时,纵向就变成了一维序列:-9,-4,-3,8
解法:初始化矩阵为0,输入矩阵(空出0行和0列),利用dp思路处理矩阵map[j][k]+=map[j][k-1],然后暴力枚举矩阵左右界,再对其纵向元素坐标进行贪心,每次贪心不断更新ans
ac代码:
//0kb 3ms
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int inf=-0xfffffff;
const int maxn=100+10;
int max(int a,int b){return a>b?a:b;}
int map[maxn][maxn];
int main()
{
int t,j,k,l;
while(scanf("%d",&t)!=EOF&&t)
{
int ans=inf; //ans初始化为无限小
memset(map,0,sizeof(map)); //初始化矩阵
for(j=1;j<=t;j++)
for(k=1;k<=t;k++)
{
scanf("%d",&map[j][k]); //输入矩阵
map[j][k]+=map[j][k-1]; //处理矩阵
}
for(j=1;j<=t;j++) //枚举左右界
for(k=j;k<=t;k++)
{
int temp=0;
for(l=0;l<=t;l++) //贪心
{
temp+=map[l][k]-map[l][j-1];
if(temp>0)ans=max(ans,temp);
else temp=0;
}
}
printf("%d\n",ans);
/* for(j=0;j<=t;j++) //输出处理后的矩阵,用于调试
{
for(k=0;k<=t;k++)
printf("%4d",map[j][k]);
cout<<endl;
}
*/
}
return 0;
}
小结:别人都说这题考的是dp,但是其实这个在我看来就是暴力加剪枝- -,而且貌似本弱最擅长的就是暴力,然后剪剪剪剪~~只要懂了如何从o(n^4)简化到o(n^3)其余的就不难下手了
中间的贪心跟另外一题是一样的,并不难,就不详说了,传送门已经给出了
有什么意见或者建议,欢迎指导~,有什么不理解的,也可以在留言板上提出,谢谢~~~