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