樹形動態規劃

問題能夠分解成若干相互聯繫的階段,在每個階段都要作出決策,所有過程的決策是一個決策序列。要使整個活動的整體效果達到最優的問題,稱爲多階段決策問題。動態規劃就是解決多階段決策最優化問題的一種思想方法。
 

階段

將所給問題的過程,按時間或空間特徵分解成若干相互聯繫的階段,以便按次序去求每階段的解

狀態

各階段開始時的客觀條件叫作狀態。

決策

當各段的狀態取定之後,就能夠作出不一樣的決定,從而肯定下一階段的狀態,這種決定稱爲決策。

策略

由開始到終點的全過程當中,由每段決策組成的決策序列稱爲全過程策略,簡稱策略。

狀態轉移方程

前一階段的終點就是後一階段的起點,前一階段的決策選擇導出了後一階段的狀態,這種關係描述了由k階段到k+1階段狀態的演變規律,稱爲狀態轉移方程。

目標函數與最優化概念

目標函數是衡量多階段決策過程優劣的準則。最優化概念是在必定條件下找到一個途徑,通過按題目具體性質所肯定的運算之後,使全過程的總效益達到最優。
大多數動規都是在一維二維這種規則的背景下的,能夠解決的問題比較侷限,而樹做爲一種特殊的圖,能夠描述比較複雜的關係,再加上樹的遞歸定義,是一種很是合適動規的框架,樹型動態規劃就成爲動規中很特殊的一種類型。
 

樹形動態規劃基本上能夠分爲2個部分,一個是建樹,另外一個就是動態規劃,一個好的數據結構,能使你編程很是容易,這也是樹形動態規劃的難點之一

典型例題

沒有上司的晚會等
【問題描述】
有個公司要舉行一場晚會。爲了讓到會的每一個人不受他的直接上司約束而能玩得開心,公司領導決定:若是邀請了某我的,那麼必定不會再邀請他的直接的上司,但該人的上司的上司,上司的上司的上司……均可以邀請。已知每一個人最多有惟一的一個上司。
已知公司的每一個人參加晚會都能爲晚會增添一些氣氛,求一個邀請方案,使氣氛值的和最大。
【輸入:】
第1行一個整數N(1<=N<=6000)表示公司的人數。
接下來N行每行一個整數。第i行的數表示第i我的的氣氛值x(-128<=x<=127)。
接下來每行兩個整數L,K。表示第K我的是第L我的的上司。
輸入以0 0結束。
【輸出】:
一個數,最大的氣氛值和。
【樣例輸入】
7
1
1
1
1
1
1
1
1 3
2 3
6 4
7 4
4 5
3 5
0 0
【樣例輸出】
5
【分析】
如上例,上司與小兵之間的關係構成一棵樹。
5
| \
3 4
| \ | \
1 2 6 7
又是求最優解,而且每個節點的取捨關乎到全局 所以,此題可用樹形動態規劃
咱們可用f[v][0]存儲不選編號爲V的節點的最優解,f[v][1]存儲選編號爲V的節點的最優解
 
//大數組的定義最好不要寫在函數裏,這樣會使函數棧控件不足 

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define M 1000	//數組最大長度 

int shu[M][M],xb[M][M],shs[M],qf[M],f[M][2];
int main()
{
	
	int i,j,l,k,n,maxlev,s,x,a,b;
	
	memset(shu,0,sizeof(shu));
	memset(xb,0,sizeof(xb));
	memset(shs,0,sizeof(shs));
	memset(f,0,sizeof(f));
	
	//一、建樹 
	scanf("%d",&n);
	for(i=1;i<=n;i++)scanf("%d",&qf[i]);
	
	l=k=1;
	while(l&&k)
	{
		scanf("%d%d",&l,&k);
		shs[l]=k;
		xb[k][0]++;
		xb[k][xb[k][0]]=l;
	}
	
	maxlev=-1;
	for(i=1;i<=n;i++)
	{
		x=shs[i],s=1;
		while(x!=0){s++;x=shs[x];}
		shu[s][0]++;
		shu[s][shu[s][0]]=i;
		if(s>maxlev)maxlev=s;
	}
	
	//二、動態規劃
	 for(i=maxlev;i>0;i--)
	 {
	 	for(j=1;j<=shu[i][0];j++)
	 	{
	 		if(xb[shu[i][j]][0]==0)
	 		{
	 			f[shu[i][j]][0]=0;
	 			f[shu[i][j]][1]=qf[shu[i][j]];
	 		}
	 		else
	 		{
	 			f[shu[i][j]][0]=0;
	 			f[shu[i][j]][1]=qf[shu[i][j]];
	 			for(k=1;k<=xb[shu[i][j]][0];k++)
	 			{
	 				a=f[xb[shu[i][j]][k]][0];b=f[xb[shu[i][j]][k]][1];
	 				
	 				f[shu[i][j]][1] +=a;//若是要當前節點,則不能取下部節點 
	 				
	 				//若是不要當前節點,則可要可不要下部節點,取使得氣氛值最大的方案 
					if(b>a)a=b;
	 				f[shu[i][j]][0] +=a;
	 			}
	 		}//狀態轉移 
	 	}
	 }
	 
	 s=0;
	 for(i=1;i<=shu[1][0];i++)//從樹根獲取最優方案
	 {
	 	a=f[shu[1][i]][0];b=f[shu[1][i]][1];
	 	if(b>a)a=b;
	 	s+=a;
	 }
	 
	 printf("最大氣氛值:%d\n",s); 
	
	return 0;
}
相關文章
相關標籤/搜索