1. 程式人生 > >計蒜客 挑戰難題 跳躍遊戲二

計蒜客 挑戰難題 跳躍遊戲二

給定一個非負整數陣列,假定你的初始位置為陣列第一個下標。

陣列中的每個元素代表你在那個位置能夠跳躍的最大長度。

你的目標是到達最後一個下標,並且使用最少的跳躍次數。

例如:

A = [2,3,1,1,4], 到達最後一個下標的最少跳躍次數為2.(先跳躍1步,從下標0到1,然後跳躍3步,到達最後一個下標。一共兩次)

格式:

第一行輸入一個正整數n,接下來的一行,輸入陣列A[n]。

最後輸出最少的跳躍次數。

樣例輸入

5
3 1 1 1 1

樣例輸出

2
題解:
利用動態規劃,模擬揹包問題;從最後出發dp[i]=main(dp[i],dp[j]+1);
依次向前查詢,dp[i]表示第i個到最後一個的最短步數;
#include<stdio.h>
#include<algorithm>
#include<iostream>
using namespace std;
int main()
{
	int a[1000],dp[1000],n,i,j;
	scanf("%d",&n);
	for(i=0;i<n;i++)
	{
		scanf("%d",&a[i]);
	}
	dp[n-1]=0;
	for(i=n-2;i>=0;i--)
	{dp[i]=n;
		for(j=i;j<n&&j<=i+a[i];j++)
		{
			dp[i]=min(dp[i],dp[j]+1);
		}
	
	}	printf("%d\n",dp[0]);
}

另附其他理解:

先給出狀態轉移方程 d[i]=min(d[i],d[j]+1)(i<j<=n-1&&j<=I + a[i],d[n-1]=0),d[i]代表對於第 i 個數 其到達n – 1所需的最小步數, 對於 i 顯然左邊方程是正確的,因為一個數 a i

可以跳躍到的數中理應跳躍到 到達n – 1 所需步數最小的位置,跳到其他的位置不可能花更少的步數。

總結(吐槽?): 動態規劃的題目就這樣,基本給出方程來就沒什麼好說的了,這道題目被劃分在動態規劃的題目裡,所以直接往這個方向想,答案一下子就出來了

題目的解與狀態恰好一樣。這是我靠自己做出來的第一道動態規劃的題目,此前經典例題做過很多但都是看了題解的,所以,讓我非常有成就感,在此簡單歸納一下

Dp題目的特點。

  1. . 可以劃分為若干的子問題
  2. .由區域性解可求得全域性解
  3. . 往往需要遞推公式或遞迴解題
  4. .子問題的解往往拓撲有序,比如這道題 求d[i]必須先知道d[i+1]到d[n-1]的值,且不能通過d[i]求d[i+1]到d[n-1];

由以上特性我們可以明白那些題目適合用dp解決,其實特性3是由特性4所決定的,做dp題目關鍵就是狀態轉移方程的設計,首先要先想好狀態

可以從問題解入手,因為出題者考查的是動規的話,往往有意無意讓狀態與解接近,為了設計合理的狀態,對題目適當的數學抽象也是必要的,然後根據子問題

的劃分著手設計方程,動規其實是一種思想,根據已有解進一步推出全域性解,讓答案"動態生成",其實關於dp很重要的一點是可能的重複計算,遞推是一種消除的

方法,還有的方法是記憶化搜尋。最後要說的就是dp一般都能給出有令人滿意的時間複雜度的演算法,但是他絕不是最優的,題目可能存在更優的貪心演算法,這道題目

叫做跳躍遊戲二,跳躍遊戲的改進版(其實更簡單。。),那道題就是利用貪心的策略,但那道也可以使用dp解決。dp的一些特性貪心也是滿足的