#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; }
: