cugb 1050 導彈攔截(動態規劃,LIS)

 

聽說這個這個呢~~~是動態規劃的典型類題,叫最長上升子序列(LIS),但這個題是最長不上升子序列,原理一樣哈,那就來分析一下~~

LIS:

有一串數,比如1 3 5 7 9 2 4 6 8,求最長上升子序列中,元素的個數。

分析的方法,據說叫貪心``就是化大爲小:設一個dp數組,來記錄每一個元素和它之前的所有元素組成的最長上升子序列中元素的個數,可以看到子問題和原問題是相同的,只是規模(N)變小了,解題方法是由小規模的結果推出原規模的結果,這叫不叫遞歸呢...?有點像..

S1:從第一個元素開始,只有他自己,所以dp[1]=1;

s2:第二個元素和它之前的,因爲1 3組成了上升序列,所以dp[2]=2

s2,第三個元素和它之前的,1,3,5,因爲1 3 5,上升,所以dp[3]=2;

以此類推,過了9時,dp[5]=5;

s6:元素爲2,9>2結束了上升,但並不意味着dp[6]=dp[5]=5,因爲2之前,比它小且組成上升的,只有第一個元素1,所以這裏dp[6]=2

……

所以dp[]爲:1 2 3 4 5 2 3 4 5

我原來錯在,以爲dp[i]=dp[i-1]+(0 or 1),呃..是沒理解這種算法的含義

現在知道了,每個元素的dp值,是僅比它小的元素的dp值+1,比如第8個元素6,僅比它小的是5,而5的dp爲3,加1就是6的dp值:4。說白點呢,就是因爲要求的是上升序列,目標元素(設爲j,i && j < i),若前j個是上升狀態,那麼加上i以後,就變成前i個都是上升狀態,自然dp值是要加上1的。

==============================================

就導彈攔截這個題呢,雖然是最長不上升序列,但道理都是一樣的,解決起來改兩個地方就可以了

1,再用一個數組存逆序,把下降變成上升求就好了

2,注意多了個等號,300 300時,dp是要加一的

下面兩段代碼,第一個是這個題的,第二個是我自己寫的LIS,嘻嘻~~~開心開心

 

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <algorithm>
using namespace std;

int num1[100];
int num2[100];
int n;

int nlis()    //not lis~~
{
	int dp[100];
	int i, j;
	int each_e_dp;
	int max_dp;
	memset( dp,0,sizeof(dp) );
	dp[1] = 1;
	each_e_dp = 0;
	
	for (i = 2 ; i <= n ; i++)
	{
		for (j = 1 ; j < i ; j++)
		{
			if (num2[j] <= num2[i] && each_e_dp < dp[j])    //等號注意不能掉 
			{
				each_e_dp = dp[j];
			}
		}
		dp[i] = each_e_dp + 1;
		each_e_dp = 0;
	}
	
	max_dp = 0;                 //求最大dp,快排,起泡,怎麼都行,數據不大。 
	for ( i = 1 ; i <=n ; i++)
	{
		if ( dp[i] > max_dp )
		{
			max_dp = dp[i];
		}
	}
	return max_dp;
	
}
int main()
{
	int k;
	int i;
	int max_dp;
	k = 1;
	memset(num1,0,sizeof(num1));
	memset(num2,0,sizeof(num2));
	
	while(scanf("%d", &n ) != EOF)
	{
		for(i = 1; i <= n; i++)
		{
			scanf("%d", &num1[i]);
			
		}
		for(i = n; i >= 1; i--)
		{
			num2[k++] = num1[i];        //逆序,講問題變爲LIS 
		}
		k = 1;
		max_dp = nlis();
		printf("%d\n", max_dp);
	}
	return 0;
}



============================================


下面是LIS~~

//LIS,最長上升子序列 
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <algorithm>
using namespace std;
int main()
{
	int dp[100];
	int num[100];
	int n, i, j;
	int max_dp = 0;
	int each_e_dp = 0;
	
	while( scanf("%d", &n) != EOF )
	{
		memset(dp,0,sizeof(dp));
		memset(num,0,sizeof(num));
		
		for (i = 1; i <= n; i++)
		{
			scanf("%d", &num[i]);
		}
		dp[1] = 1;
		each_e_dp = 0;
		
		for (i = 2 ; i<= n ; i++)
		{
			for (j = 1; j < i ; j++)
			{
				if ( num[j] < num[i] && each_e_dp < dp[j] )
				{
					each_e_dp = dp[j];
				}
			}
			dp[i] = each_e_dp + 1;
			each_e_dp = 0;
			
		}
		for (i = 1 ; i <= n ; i++)
		{
			if (dp[i] > max_dp)
			{
				max_dp = dp[i];
			}
		}
	 	printf("%d\n", max_dp);
		max_dp = 0;
	}
	system("pause");
	return 0;
}


 

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