計算機機試一動態規劃例題總結(適合入門)

動態規劃可能是算法裏邊最難的,也可能是機試裏最難的,所以作爲小白,最好是能積累,豐富自己的題庫,以下是我在刷保/考研究生機試題的動態規劃的內容,都比較簡答,以後遇到類似題目還會不斷更新。

感謝計算機機試羣裏的大佬提供我們練習的機會。羣號:299565515

一、走樓梯問題

動態規劃問題雖然代碼比較簡單,但是在構造遞推式時候是最難的,這個題的遞推式大家肯定都做過,沒錯,就是斐波那契數列的遞推式。F(n)=F(n-1)+F(n-2)。

爲什麼是這樣呢?

首先我們可以從最後一層樓梯考慮。假設有10層臺階,那麼每次只能走一層臺階或者兩層臺階的話,我可以從第8層臺階和第9層臺階走到第10層臺階。也就是說 第10層臺階的走法數=第8層臺階的走法數+第9層臺階的走法數

即F(10)=F(8)+F(8)。因此就推導出了我們的推導式。那麼動態規劃的邊界是哪兒呢?

通過分析題意,我們可以看到,我們處於第一級,所以F(1)=0,F(2)=1,F(3)=2,這些都是很容易得到的,有了這些,我們就可以寫代碼了。

#include<iostream>
using namespace std;
const int n=40;
int F[n]; 
int main()
{
	int M;
	while(cin>>M)
	{
		F[1]=0;F[2]=1;F[3]=2;
		for(int i=4;i<=M;i++)
			F[i]=F[i-1]+F[i-2];
		printf("%d\n",F[M]);
	}
	return 0;
}

二、最長子列和問題

最長子列和問題可以說是最常見的動態規劃問題了,我至少見過3次。

這個問題有很多種解法,包括暴力的方法,分治思想的遞歸方法,還有動態規劃方法等。

下邊我主要介紹暴力和動態規劃的方法,因爲暴力當時沒有過,所以採用動態規劃的方法,後來過了。

1.暴力:

這道題是尋找最長子序列串,並且找出構成最長子序列串的首個數字和最後一個數字。

我的思想是可以通過遍歷依次尋找,第一次可以只找一個數字,然後遍歷一圈數組,找出最大的存起來,第二次可以找兩個數字作爲一組,然後類似滑動窗口對數組進行遍歷,然後最後到string.size()這麼長的數字作爲一組(只有一個)

方法很通俗易懂,但是時間複雜度比較高。O(n的3次方)。

代碼如下:

void baoli()
{
	int beg,ed,max=-99999,record=0;
	int flag1,flag2;
	for(int i=1;i<=n;i++) //n種窗口大小 
	{
		for(int j=0;j+i<=n;j++)
		{
			int k;
			for(k=j;k<j+i;k++)
				record+=vec[k];
			if(record>max ||(record==max&&(j<=flag1&&j+i-1<=flag2)))
			{ 
				max=record;
				beg=vec[j];
				ed=vec[j+i-1];
				flag1=j;
				flag2=j+i-1;
			}
			record=0;
		} 
	}
	printf("%d %d %d\n",max,beg,ed);
} 

 2.動態規劃

這個題的動態規劃是最難想的,也是時間複雜度最低的吧。

我們可以這樣表示,dp[i]表示,以dp[i]結尾的元素的最長子序列和

通俗來說就是,dp[i]存儲的是i和i前的最長子序列和,有人說了,如果i後邊是正數,那麼相加肯定比dp[i]大,這個就不用i這層去考慮了,dp[i+1]層自然會考慮進去,通過分析,我們發現,dp[i]=max{dp[i-1]+a[i],a[i]},     a[i]表示數組中存的輸入的子序列。

當前的最長子序列和=上一層的最長子序列和+數組中的當前層的 數和 當前單個數的中間的最大值。

代碼如下:

const int maxn=10010;
int in[maxn],dp[maxn];//dp[i]表示以dp[i]結尾的最大子序列和 
int p[maxn][2];
void dpway()
{
	dp[0]=in[0];
	p[0][0]=in[0];p[0][1]=in[0];
	for(int i=1;i<n;i++)
	{
		if(in[i]>=dp[i-1]+in[i])
		{
			dp[i]=in[i];
			p[i][0]=in[i];
			p[i][1]=in[i];
		}
		else
		{
			dp[i]=dp[i-1]+in[i];
			p[i][0]=p[i-1][0];
			p[i][1]=in[i];
		}
	}
	int max=-99999;int left=0;int right=0;
	for(int i=0;i<n;i++)
	{
		if(max<dp[i])
		{
			max=dp[i];
			left=p[i][0];
			right=p[i][1];
		}
	}
	printf("%d %d %d\n",max,left,right);
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章