最大子矩阵

#include<iostream>
using namespace std;
#define MAX 100010
//用你自己的思维解决问题

long long v[MAX],height[MAX],dp[MAX],maxn;
int main(){
    int n;
    while(cin>>n){
        if(n==0) break;
        memset(height,0,sizeof(height));
        memset(dp,0,sizeof(dp));
        memset(v,0,sizeof(v));
        for(int i=0;i<n;i++)
            cin>>height[i];
        dp[0]=height[0];
        v[0]=height[0];
    for(int i=1;i<n;i++){
    if(v[i-1]>height[i]){//连成一片截别人
        v[i]=height[i];
        dp[i]=(dp[i-1]/v[i-1]+1)*height[i];
     }
     else {  //连成一片截自己
       if(dp[i-1]+v[i-1]>=height[i]){
        v[i]=v[i-1];
        dp[i]=dp[i-1]+v[i];
       }
         else{  // 自己独成一片
        v[i]=height[i];
        dp[i]=height[i];
         }
        }
    }
     maxn=0;
    for(int i=0;i<n;i++){
        if(dp[i]>maxn)
            maxn=dp[i];
    }
  cout<<maxn<<endl;
    
    }
    return 0;
}

 觉得自己挺对的,一般测试数据都能过,但是没有A,到底是哪里出了问题,理一下思路吧

要找出最大子矩阵,那么对于当前这块木板,

1)如果它比左边的矩阵的高度短,那么肯定是截取左边的矩阵,使其高度和自己一样高

2)如果它比左边矩阵的高度大的话,那么可以考虑截取自己的高度,和左边矩阵的高度一样,还是自己独立成为一个新的矩阵

有一种思路是对于每个单位矩阵,求每个矩形向2边延伸的最大长度,用2个数组来记录,l[i],表示第i个矩形左边的最大下标,

r[i] ,表示第i个矩阵右边的最大下标。 

这样每个人矩阵的面积就可以为

S[i]=(r[i]-l[i]+1)*height[i];

最后求出最大的s[i];

感觉这种思维比起我的,更宏观一点,突然发现我的思维是有问题的,在第一点那个地方,如果所谓的左边的那个矩阵的左边的高度比当前这个还大呢,那样我们就可以一同截取了,所以我的思维是错误的。不好意思~~,算法就是让我们的思维更加缜密~~

那么如何找到l[i]呢,一个一个地比较吗?这时动规排上了用场

右扫一遍,求出每个点的l保存在l[]数组里,然后从右到左扫一遍,求出每个点的r保存在r[]数组里,最后可以求出最大的矩阵了。

利用动态规划,如果它左边高度大于等于它本身,那么它左边的左边界一定满足这个性质,再从这个边界的左边迭代下去

正确代码:

#include<iostream>
using namespace std;
#define MAX 100010
//用你自己的思维解决问题

long long height[MAX],l[MAX],r[MAX],maxn,S[MAX];
int main(){
    int n;
	long long t;
    while(cin>>n){
        if(n==0) break;
        memset(height,0,sizeof(height));
        memset(l,0,sizeof(l));
        memset(r,0,sizeof(r));
		memset(S,0,sizeof(S));
        for(int i=1;i<=n;i++)
            cin>>height[i];
	  l[1]=1;r[n]=n;
		 for(int i=2;i<=n;i++)//求每个点左边连续比它大的最左边的下标,保存在l[]数组里
      {
          t=i;
		  while(t>1&&height[i]<=height[t-1]) 
              t=l[t-1];
          l[i]=t;
      }
      for(int i=n-1;i>=1;i--)//求每个点右边连续比它大的最右边的下标,保存在r[]数组里
      {
          t=i;
          while(t<n&&height[i]<=height[t+1])
              t=r[t+1];
          r[i]=t;
      }
		maxn=0;
		for(int i=1;i<=n;i++){
			S[i]=(r[i]-l[i]+1)*height[i];
			if(S[i]>maxn)
				maxn=S[i];
		}

		cout<<maxn<<endl;
	}
	return 0;
}

  

原文地址:https://www.cnblogs.com/wintersong/p/4982945.html