【HDU】1081 To The Max
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1081
初步看到这种题目的时候第一思路肯定是暴力,O(n^4) …… = = …… 显然不行
然后,就得想办法优化,想了半天,没辙,于是放弃了。
———去年的时候的真实想法
今年再做的时候,emm… 不就是DP么?(因为是在DP专题练习的时候twinkle给拉出来再做的) 肯定有办法的吧,再想想…
慢慢的,思路涌出来了,整个过程回放:
求所有子矩阵的最大的和,他会和DP扯上什么关系呢?
后来不知yy了多久,突然想到了一道dp基础题:http://acm.hdu.edu.cn/showproblem.php?pid=1231
这两道题目的共同点在于都是求最大连续子段的和……
顺着这个想法下去,很快又想到去年学习某个算法(名字在我脑中已经置零了…… = = )时,将一个多元、多维问题转化为一元……
接着我的第一个idea就诞生了!(不过,这个方法和网上大神们的方法相比就逊色多了……)

如图:(额… 我的画图水平就真的只有这么点儿了,不要见怪…) PS: 前提假设矩阵下标是从0~n-1
首先建立一个3维数组row[k][i][j],k:代表压缩的长度 (1<=k<=n),i代表所在的起始层数 (0<=i<=n-1),j代表列数 (0<=j<=n-1)。 那么row[k][i][j] = ∑(k=i~k=n-i)∑(i=0~n-1)∑(j=0~n-1) matrix[i][j]。
创建好row[][][]数组之后,只需要在k、i这两维上进行求 最大连续子序列 即可。
我个人感觉这种做法就类似于将一个二维的矩阵压缩成一维,虽然这里我用的是三维数组来存储,但在逻辑上(这个说法感觉有点猥琐…)还是降到一维了……
很挫的代码如下:
Build row
memset(row,0,sizeof(row)); for(k=0; k<n; ++k) for(i=k; i<n; ++i) for(j=0; j<n; ++j){ if(i==k) row[k][i][j] = mat[k][j]; else row[k][i][j] = mat[i][j]+row[k][i-1][j]; }
Get maxnumber
1 tmax=0; 2 max = -1*MAXN*MAXN*MAXN; 3 4 for(k=0; k<n; ++k){ 5 tmax = 0; 6 for(i=k; i<n; ++i){ tmax = 0; 7 for(j=0; j<n; ++j){ 8 tmax+=row[k][i][j]; 9 if(tmax<=0) tmax = 0; 10 if(max<tmax) max = tmax; 11 } 12 } 13 } 14 cout<<max<<endl;
但是写完后提交的结果是TLE……
我顿时杵在电脑前了,碎了一地的心那…… (后来回过头检查代码的时候,发现是 while(~scanf("%d",&n)) 的时候~没有加,又伤了一地的心)
于是百度了这道题目的做法,这才有缘认识到大神们的做法。
tmax=0; max = -1*MAXN*MAXN*MAXN; for(k=0; k<n; ++k){ memset(row,0,sizeof(row)); for(i=k; i<n; ++i){ for(j=0; j<n; ++j){ row[j]+=mat[i][j]; } tmax=GetMax(); if(max<tmax) max= tmax; } } cout<<max<<endl;
其实两种做法的本质还是一样的,只是就代码的精简、美观等角度看来,还是大神们的更好啊~~
这次也学习到啦!

浙公网安备 33010602011771号