HNU暑假程序设计训练 0419
目錄
題目描述
思路分析
AC代碼
深入思考
題目描述
給出一個由n個正整數組成的數組。您的任務是找到給定數組的遞增子數組的最大長度。
遞增子數組由數組中若干個連續元素組成,且子數組中的每個元素嚴格地大于前一個元素。
【輸入形式】
第一行為一個正整數n(1≤n≤),表示數組元素的個數
第二行給出n個正整數a1?a2......an? (1≤ai≤) ,整數之間使用空格分隔
【輸出形式】
輸出最大遞增子數組的長度
【樣例輸入】
【樣例輸出】
3【樣例說明】
1 7可以構成一個遞增子數組
2 11 15可以構成一個遞增子數組
所以本樣例的輸出結果為3
思路分析
直接采用窮舉法,二重循環遍歷,時間復雜度為O()。
設一個數組int arr:
| 0 | 1 | 2 | 3 | 4 |
| 1 | 7 | 2 | 11 | 5 |
設整型變量cnt=1(任意長度大于0數組的最長連續遞增子序列最小長度為1),記錄當前子數組最長連續遞增子序列的長度。子數組分割方法如下:
| 第一次 | arr[0],arr[1],arr[2],arr[3],arr[4] | cnt=2 |
| 第二次 | arr[1],arr[2],arr[3],arr[4] | cnt=1 |
| 第三次 | arr[2],arr[3],arr[4] | cnt=3 |
| 第四次 | arr[3],arr[4] | cnt=1 |
| 第五次 | arr[4] | cnt=1 |
最終結果輸出3。
AC代碼
#include <iostream> #include<stdio.h> using namespace std; int arr[100000]={0}; int main() {int n;cin >> n;for(int i=0;i<n;i++){scanf("%d",&arr[i]);}int Max=0;for(int i=0;i<n;i++){int cnt=1;for(int j=i;j<n-1;j++){if(arr[j]<arr[j+1]){cnt++;}else{break;}}if(cnt>Max)//取所有cnt中的最大值{Max=cnt;}}printf("%d\n",Max); }深入思考
其實這題是一個典型的動態規劃問題的變式。
動態規劃基本知識:
?動態規劃算法通常用于求解具有某種最優性質的問題。在這類問題中,可能會有許多可行解。每一個解都對應于一個值,我們希望找到具有最優值的解。動態規劃算法與分治法類似,其基本思想也是將待求解問題分解成若干個子問題,先求解子問題,然后從這些子問題的解得到原問題的解。與分治法不同的是,適合于用動態規劃求解的問題,經分解得到子問題往往不是互相獨立的。若用分治法來解這類問題,則分解得到的子問題數目太多,有些子問題被重復計算了很多次。如果我們能夠保存已解決的子問題的答案,而在需要時再找出已求得的答案,這樣就可以避免大量的重復計算,節省時間。我們可以用一個表來記錄所有已解的子問題的答案。不管該子問題以后是否被用到,只要它被計算過,就將其結果填入表中。這就是動態規劃法的基本思路。具體的動態規劃算法多種多樣,但它們具有相同的填表格式。
動態規劃算法跟數組有著密切的關系,因此推薦大家在分析動態規劃的算法時畫一張表格(建議使用excel)分析解決問題往往能夠事半功倍。
(引自?CSDN博主「靜篤歸心方得平和心氣]
原文鏈接:https://blog.csdn.net/weixin_42182348/article/details/90814032)
最大遞增子數組問題(不要求連續)
給定數組arr,返回arr的最長遞增子序列(Longest increasing subsequence,LIS)的長度,比如arr=[2,1,5,3,6,4,8,9,7],最長遞增子序列為[1,3,4,8,9]返回其長度為5。
那么,這個問題怎么用動態規劃法求解呢?
設f[i]表示必須以arr[i]結尾的所有子數組的LIS。要計算f[i],就要考察i之前的所有位置(0到i-1,這就是代碼內層for的控制變量j的變化范圍),找到最大的f[j]。f[j]代表以arr[j]結尾的子數組中最大遞增子序列的長度。
注意到,由于它是遞增的,因此arr[j]就是子序列的最大值。如果arr[i]比arr[j]還大,那就一定大于該序列中的其他數,能夠構成一個長度+1的LIS。這就是if中的第一個條件的來源。
第二個條件是為了保證更新f[i]的結果是得到更大的f[i]值。說起來不太直觀,請看下表。
| 序號i | 0 | 1 | 2 | 3 | 4 | ... |
| arr[i] | 11 | 13 | 19 | 5 | 21 | ... |
| f[i] | 1 | 2 | 3 | 1 | ? | ... |
此刻i=4。假設沒有if中的第二個條件(f[i]<f[j]+1),求f[4]的詳細過程為:
| j | 0 | 1 | 2 | 3 |
| f[4] | 2 | 3 | 4 | 2 |
arr[0]<arr[4]? ? ? ? ? ? ? ? ? ? ? ? ? ? ?f[4]=f[0]+1=2
arr[1]<arr[4]? ? ? ? ? ? ? ? ? ? ? ? ? ? ?f[4]=f[1]+1=3
arr[2]<arr[4]? ? ? ? ? ? ? ? ? ? ? ? ? ? ?f[4]=f[2]+1=4
arr[3]<arr[4] 但是此時f[3]=1,f[4]=4(見上一行), 不滿足f[i]<f[j]+1。更新后?f[4]=f[3]+1=2(反而變小了)
而帶上(f[i]<f[j]+1)這個條件的話,j=3這次循環就不會更新f[4]的值,最終算出f[4]的正確值為4。
代碼
#include <iostream> #include<stdio.h> using namespace std; int arr[100000]={0}; int f[100000]={0};//記錄子數組的LIS。 int main() {int n;cin >> n;for(int i=0;i<n;i++){cin >> arr[i];f[i]=1;//初始化}int Max=0;//記錄以不同元素結尾的子數組的LIS的最大值。for(int i=1;i<n;i++){for(int j=0;j<i;j++){if((arr[j]<arr[i])&& (f[i]<f[j]+1)){f[i]=f[j]+1;//f[i]記錄了必須以arr[i]結尾時所有子數組的LIS。}}if(f[i]>Max){Max=f[i];}}cout << Max << endl;return 0; }總結
以上是生活随笔為你收集整理的HNU暑假程序设计训练 0419的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 串的详细讲解
- 下一篇: 随手练——字符串按最小(大)字典序拼接