日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

最大连续和问题

發布時間:2024/5/6 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 最大连续和问题 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

給出一個長度為n的序列A1,A2,…,An,求最大連續和。換句話說,要求找到1<=i<=j<=n,使得Ai+Ai+1+…Aj盡量大。

暴力枚舉實現

#include <iostream> using namespace std; int A[50]={5,9,7,3,4,1,5,8,6,7,3,6,4,0,8,6,7}; int main() {int n=50;int tot=0;int best=A[0];//初始化最大值,為了防止連續和小于0,所以必須初始化為A[0]。for(int i=0;i<n;i++){for(int j=i;j<n;j++){//檢查連續子序列A[i],…,A[j]int sum=0;for(int k=i;k<=j;k++){//累加元素和sum+=A[k];tot++;}if(sum>best){best=sum;}}}cout<<"best="<<best<<' '<<"tot="<<tot<<endl;return 0; }

tot與機器的運行速度無關。
不同機器的速度不一樣,運行時間也會有所差異,但tot的值一定相同。
換句話說,它去掉了機器相關的因素,只衡量算法的“工作量”大小,
具體來說,是“加法”操作的次數。

算法分析:

1.第一層循環遍歷數組A的i位從0到n,是最大連續和的左起點;
2.第二層循環遍歷數組A的j位從i到n,是最大連續和的右終點;
3.第三層循環遍歷數組A的k位從i到j,求出當前范圍內的連續和;
4.公式:設輸入規模為n時的加法操作次數
T(n)= ∑i=1n∑j=inj?i+1\displaystyle\sum_{i=1}^{n} \displaystyle\sum_{j=i}^{n} j-i+1i=1n?j=in?j?i+1=∑i=1n\displaystyle\sum_{i=1}^{n}i=1n? (n?i+1)(n?i+2)2\frac{(n-i+1)(n-i+2)}{2}2(n?i+1)(n?i+2)?=n(n+1)(n+2)6\frac{n(n+1)(n+2)}{6}6n(n+1)(n+2)?

連續子序列之和等于兩個前綴和之差實現

#include <iostream> using namespace std; int A[50]={5,9,7,3,4,1,5,8,6,7,3,6,4,0,8,6,7}; int S[50]; int main() {int n=50,best=A[0];S[0]=0;for(int i=0;i<n;i++){S[i]=S[i-1]+A[i];//遞推前綴和S}for(int i=0;i<n;i++){for(int j=i;j<n;j++){best=max(best,S[j]-S[i-1]);//更新最大值}}cout<<"best="<<best<<endl;return 0; }

算法分析:

S[i]表示第1個數到第i個數的和,S[j]-S[i-1]表示第i個數到第j個數列的和。
T(n)=∑i=1nn?i+1\displaystyle\sum_{i=1}^{n} n-i+1i=1n?n?i+1=n(n+1)2\frac {n(n+1)}{2}2n(n+1)?

分治算法實現

#include <iostream> using namespace std; int A[50]={5,9,7,3,4,1,5,8,6,7,3,6,4,0,8,6,7}; int maxsum(int *A,int x,int y) {//返回數組在左閉右開區間[x,y)中的最大連續和if(y-x==1) return A[x]; //只有一個元素,直接返回。int m=x+(y-x)/2;//分治第一步:劃分成[x,m)和[m,y)int maxs=max(maxsum(A,x,m),maxsum(A,m,y));//分治第二步:遞歸求解int v,L,R;v=0,L=A[m-1];//分治第三步:合并(1)——從分界點開始往左的最大連續和Lfor(int i=m-1;i>=x;i--){L=max(L,v+=A[i]);}v=0,R=A[m];//分支第三步:合并(2)——從分界點開始往右的最大連續和Rfor(int i=m;i<y;i++){R=max(R,v+=A[i]);}return max(maxs,L+R); //把子問題的解與L和R比較 } int main() {cout<<maxsum(A,0,51)<<endl;return 0; }

分治算法實現:
1.劃分問題:把序列分成元素個數盡量相等的兩半;
2.遞歸求解:分別求出完全位于左半或者完全位于右半的最佳序列;
3.合并問題:求出起點位于左半,終點位于右半的最大連續和序列,并和子問題的最優解比較。

思路分析

首先,我們可以把整個數列平均分成左右兩部分,答案則會在以下三種情況中:
1、所求數列完全包含在左半部分的數列中。
2、所求數列完全包含在右半部分的數列中。
3、所求數列剛好橫跨分割點,即左右數列各占一部分。
前兩種情況和大問題一樣,只是規模小了些,如果三個子問題都能解決,那么答案就是三個結果的最大值。

計算出:以分割點為起點向左的最大連續數列和、以分割點為起點向右的最大連續數列和,這兩個結果的和就是第三種情況的答案。因為已知起點,所以這兩個結果都能在O(N)的時間復雜度能算出來。

算法分析:

用遞歸的思路進行分析,設序列長度為n時T(n)=2T(n/2)+n,T(1)=1;
其中2T(n/2)是兩次長度為n/2的遞歸調用,而最后的n是合并的時間(整個序列恰好掃描一遍)。
注意分界點應當是x和y的平均數m=x+(y-x)/2,這是因為運算符“/”的“取整”朝零方向(towards zero)
的取整,而不是向下取整用x+(y-x)/2來確保分界點總是靠近區間起點。

動態規劃實現

#include <iostream> using namespace std; int A[50]={0,5,9,7,3,4,1,5,8,6,7,3,6,4,0,8,6,7}; int main() {int ans=A[1];for(int i=1;i<50;i++){if(A[i-1]>0)A[i]+=A[i-1];else A[i]+=0;if(A[i]>ans) ans=A[i];}cout<<ans<<endl;return 0; }

算法分析

用dp[n]表示以第n個數結尾的最大連續子數列的和,于是存在以下遞推公式:
dp[n] = max(0, dp[n-1]) + num[n]
則整個問題的答案是max(dp[m]) | m∈[1, N]。

大道至簡——完美解決實現

#include <iostream> using namespace std; int main() {int N,n,s,ans,m=0;cin>>N>>n; //讀取數組長度和數列中的第一個數ans=s=n; //把ans初始化為數列中的的第一個數for(int i=1;i<N;i++){if(s<m) m=s;cin>>n; s+=n;if(s-m>ans)ans=s-m;}cout<<ans<<endl;return 0; }

已知一個sum數組,sum[i]表示第1個數到第i個數的和,于是sum[j] - sum[i-1]表示第i個數到第j個數的和。

以第n個數為結尾的最大子數列,假設這個子數列的起點是m,于是結果為sum[n] - sum[m-1]。

并且,sum[m]必然是sum[1],sum[2]…sum[n-1]中的最小值。
這樣,如果在維護計算sum數組的時候,同時維護之前的最小值, 那么答案也就出來了。

在計算前綴和的過程中維護之前得到的最小值。
它的時間復雜度是O(N),空間復雜度是O(1),這達到了理論下限!

最大連續和問題,解決!

總結

以上是生活随笔為你收集整理的最大连续和问题的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。