最長有序子序列—動態規劃算法

動態規劃使用範圍:(http://baike.baidu.com/view/28146.htm

任何思想方法都有一定的侷限性,超出了特定條件,它就失去了作用。同樣,動態規劃也並不是萬能的。適用動態規劃的問題必須滿足最優化原理和無後效性。   

1.最優化原理(最優子結構性質) 最優化原理可這樣闡述:一個最優化策略具有這樣的性質,不論過去狀態和決策如何,對前面的決策所形成的狀態而言,餘下的諸決策必須構成最優策略。簡而言之,一個最優化策略的子策略總是最優的。一個問題滿足最優化原理又稱其具有最優子結構性質。   

2.無後效性 將各階段按照一定的次序排列好之後,對於某個給定的階段狀態,它以前各階段的狀態無法直接影響它未來的決策,而只能通過當前的這個狀態。換句話說,每個狀態都是過去歷史的一個完整總結。這就是無後向性,又稱爲無後效性。   

3.子問題的重疊性 動態規劃將原來具有指數級複雜度的搜索算法改進成了具有多項式時間的算法。其中的關鍵在於解決冗餘,這是動態規劃算法的根本目的。 動態規劃實質上是一種以空間換時間的技術,它在實現的過程中,不得不存儲產生過程中的各種狀態,所以它的空間複雜度要大於其它的算法。

動態規劃思想:

       如果各個子問題不是獨立的,不同的子問題的個數只是多項式量級,如果我們能夠保存已經解決的子問題的答案,而在需要的時候再找出已求得的答案,這樣就可以避免大量的重複計算。由此而來的基本思路是,用一個表記錄所有已解決的子問題的答案,不管該問題以後是否被用到,只要它被計算過,就將其結果填入表中。

時間複雜度爲O(n^2),算法原理:

數組a[]爲待處理數組

f[]用於記錄a[]數組中,以對應位置數據爲結尾的最長有序序列長度

p[]用於記錄a[]數組中,以對應位置數據爲結尾的前一個數據位置

使用position記錄最大長度位置

以a[]={1,4,7,2,5,8,3,6,9},計算最長遞增有序子序列爲例

初始化f[]={1, 1, 1, 1, 1, 1, 1,1,1},p[]={0,1,2,3,4,5,6,7,8}

計算f[i]時,f[i]=max(f[j]+1) ,(其中,a[i]>a[j],i>j>=0),意思是以a[i]爲結尾,找出在a[i]前比a[i]小的數據中以該數據爲結尾的最大有序子序列長度max(f[j]),則以a[i]結尾的最大有序子序列長度爲max(f[j])+1。計算同時定義p[i]=j,標誌a[i]爲結尾的最長子序列的前一個數據a[j]的位置。同時判斷此時最大長度a[i]是否比當前最大長度max大,如果a[i]更大則更新position

a[]={1,4,7,2,5,8,3,6,9}

i=0   f[]={1,1,1,1,1,1,1,1,1},  p[]={0,1,2,3,4,5,6,7,8}

i=1   f[]={1,2,1,1,1,1,1,1,1},  p[]={0,0,2,3,4,5,6,7,8}  4>1,所以最大長度爲2,position=1

i=2   f[]={1,2,3,1,1,1,1,1,1},  p[]={0,0,1,3,4,5,6,7,8}  7>4,7>1 其中4結尾的長度爲2,所以最大長度爲3,position=2

i=3   f[]={1,2,3,2,1,1,1,1,1},  p[]={0,0,1,0,4,5,6,7,8}  2>1 所以最大長度爲2

i=4   f[]={1,2,3,2,3,1,1,1,1},  p[]={0,0,1,0,1,5,6,7,8}  5>1,5>4,5>2,其中以4結尾的長度爲2,所以最大長度爲3

i=5   f[]={1,2,3,2,3,4,1,1,1},  p[]={0,0,1,0,1,2,6,7,8}  8比前面的數據都大,所以最大長度爲4,position=5

i=6   f[]={1,2,3,2,3,4,3,1,1},  p[]={0,0,1,0,1,2,3,7,8}  3>1,3>2,其中以2結尾的長度爲2,所以最大長度爲3

i=7   f[]={1,2,3,2,3,4,3,4,1},  p[]={0,0,1,0,1,2,3,4,8}  6>1,6>4,6>2,6>5,6>3,其中以5結尾長度爲3,所以最大長度爲4

i=8   f[]={1,2,3,2,3,4,3,4,5},  p[]={0,0,1,0,1,2,3,4,5}  9比前面數據都大,所以最大長度爲5,position=8

在對所有a中元素循環過後,通過max記錄下最後數據位置,以及p記錄的前一個數據的位置,可以遞歸求出LIS

代碼如下:

#include<stdio.h>

int a[10000]={0};
int f[10000]={0};
int p[10000]={0};
int max=0;
int position =0;
void compare(int n){
	for(int i=0; i<n; i++){
		for(int j=0; j<i; j++){
			if(a[i]>a[j]){
				if(f[i]<f[j]+1){
					f[i]=f[j]+1;
					p[i]=j;
					if(f[i]>max){
						postiion=i;
						max = f[i];
					}
				}
			}
		}
	}
}

void printLIS(int position){		
	if(p[position]==position){
		printf("%d",a[position]);
		return;
	}
	printLIS(p[position]);
	printf(" %d",a[position]);
}

void main(){
	int n;
	max =0;
	position = 0;
	scanf("%d",&n);
	for(int i=0; i<n; i++){
		scanf("%d",&a[i]);
		f[i]=1;
		p[i]=i;
	}
	compare(n);
	printLIS(position);
	printf("\n");
}

 又如hdoj中的 1160 FatMouse's Speed

Problem Description
FatMouse believes that the fatter a mouse is, the faster it runs. To disprove this, you want to take the data on a collection of mice and put as large a subset of this data as possible into a sequence so that the weights are increasing, but the speeds are decreasing.


 

Input
Input contains data for a bunch of mice, one mouse per line, terminated by end of file.

The data for a particular mouse will consist of a pair of integers: the first representing its size in grams and the second representing its speed in centimeters per second. Both integers are between 1 and 10000. The data in each test case will contain information for at most 1000 mice.

Two mice may have the same weight, the same speed, or even the same weight and speed.


 

Output
Your program should output a sequence of lines of data; the first line should contain a number n; the remaining n lines should each contain a single positive integer (each one representing a mouse). If these n integers are m[1], m[2],..., m[n] then it must be the case that

W[m[1]] < W[m[2]] < ... < W[m[n]]

and

S[m[1]] > S[m[2]] > ... > S[m[n]]

In order for the answer to be correct, n should be as large as possible.
All inequalities are strict: weights must be strictly increasing, and speeds must be strictly decreasing. There may be many correct outputs for a given input, your program only needs to find one.


 

Sample Input
6008 1300 6000 2100 500 2000 1000 4000 1100 3000 6000 2000 8000 1400 6000 1200 2000 1900


 

Sample Output
4 4 5 9 7

 

代碼如下:

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

int f[10001];
int p[10001];

struct Mouse{
	int w;
	int s;
	int n;
}Mic[10001];

bool compare(const Mouse &a, const Mouse &b){
	if(a.w==b.w)
		return a.s > b.s;
	else
		return a.w < b.w;
}

void printLIS(int max_l){       
    if(p[max_l]==max_l){  
        printf("%d\n",Mic[max_l].n);  
        return;  
    }  
    printLIS(p[max_l]);  
    printf("%d\n",Mic[max_l].n);  
} 

void main(){
	int i=1,max=0,max_l=0;
	while(scanf("%d %d",&Mic[i].w,&Mic[i].s)!=EOF){
		f[i]=1;
		p[i]=i;
		Mic[i].n=i;
		i++;
	}
	sort(Mic+1,Mic+i,compare);

	for(int k=1; k<i+1; k++){
		for(int j=1; j<k; j++){
			if(Mic[j].s>Mic[k].s&&Mic[j].w<Mic[k].w){
				if((f[j]+1)>f[k]){
					f[k]=f[j]+1;
					p[k]=j;
					if(f[k]>max){
						max = f[k];
						max_l = k;
					}
				}
			}
		}
	}
	printf("%d\n",max);
	printLIS(max_l);
}


 

 

參考:

http://www.cppblog.com/jake1036/archive/2011/08/20/144727.html

http://hi.baidu.com/lewutian/item/8d13e2307d3151362f20c45a


 

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