zoukankan      html  css  js  c++  java
  • 树形动态规划

    问题可以分解成若干相互联系的阶段,在每一个阶段都要做出决策,全部过程的决策是一个决策序列。要使整个活动的总体效果达到最优的问题,称为多阶段决策问题。动态规划就是解决多阶段决策最优化问题的一种思想方法。
     

    阶段

    将所给问题的过程,按时间或空间特征分解成若干相互联系的阶段,以便按次序去求每阶段的解

    状态

    各阶段开始时的客观条件叫做状态。

    决策

    当各段的状态取定以后,就可以做出不同的决定,从而确定下一阶段的状态,这种决定称为决策。

    策略

    由开始到终点的全过程中,由每段决策组成的决策序列称为全过程策略,简称策略。

    状态转移方程

    前一阶段的终点就是后一阶段的起点,前一阶段的决策选择导出了后一阶段的状态,这种关系描述了由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));
    	
    	//1、建树 
    	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;
    	}
    	
    	//2、动态规划
    	 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
    ",s); 
    	
    	return 0;
    }
  • 相关阅读:
    jquery验证手机号码和固定电话号码
    window下安装mongodb及php mongo扩展
    Html form 表单提交前验证
    验证电话号码中间四位加※
    php方法 隐藏手机号中间四位
    win7 64位安装redis 及Redis Desktop Manager使用
    Redis系列-远程连接redis并给redis加锁
    使用密码记录工具keepass来保存密码
    【消息队列MQ】各类MQ比较
    Syslog-ng
  • 原文地址:https://www.cnblogs.com/tangshiguang/p/6770721.html
Copyright © 2011-2022 走看看