公司聚会喜欢程度计算 算法(动态规划)Dynamic Programming

问题:

     Professor Stewart is consulting for the president of a corporation that is planning a company party. The company has a hierarchical structure; that is, the supervisor relation forms a tree rooted at the president. The personnel office has ranked each employee with a conviviality rating, which is a real number. In order to make the party fum for all attendees, the president does not want both an employee and his or her immediate supervisor to attend.

     Professor Stewart is given the tree that describes the structure of the corporation, using theleft-child, right-sibling representation. Each node of the tree holds, in addition to the pointers, the name of an employee and that employee’s conviviality ranking. Describe an algorithm to make up a guest list that maximizes the sum of the conviviality ratings of the guests. Analyze the running time of your algorithm.

   Stewart教授是一家公司总裁的顾问,这家公司计划一个公司聚会。这个公司有一个层次式的结构;也就是说,管理关系形成一棵以总裁为根的树。人事部给每个雇员以喜欢聚会的程度来排名,这是个实数。为了使每个参加者都喜欢这个聚会,总裁不希望一个雇员和他(她)的直接上司同时参加。

   Stewart教授面对一棵描述公司结构的树,使用了左子女、右兄弟表示法。树中每个结点除了包含指针,还包含雇员的名字和该雇员喜欢聚会的排名。描述一个算法,它生成一张客人列表,使得客人喜欢聚会的程度的总和最大。分析你的算法的执行时间

答:

      分析:求出以每个节点为根节点的子树去或者不去的最大喜欢程度和,以此往上推,本题就是求根节点去或者不去的最大喜欢程度。显然,这具有最优子序列结构。

     给每个节点增加两个域,select,unsel,select[i]表示i节点去时,以i节点为根的子树的喜欢程度和,unsel[i]表示i节点不去时,所获得的喜欢程度和

    公式如下:

    r.select=r.data+sum(unsel[j]);          //jr的孩子,r.data为节点r的喜欢程度

    r.unsel=sum(max{unsel[j],select[j]});

   当i选择去时,它的孩子节点肯定不能去;当i不去时,其孩子节点可以选择去或者不去;

   然后根据求出的根节点的最大喜欢程度和,找出参加的名单。

 

首先是计算每个节点为根的子树的最大喜欢程度和。

typedef struct Node

{

    int data;//表示喜欢聚会的程度

    int *parent,*lchild,*rsibling;//左孩子,右兄弟结构

    int select,unsel;//这两个值在初始化树时,均为零

    int go;//标识当前节点是否参加聚会

}Node;

 

typedef struct stack{

   int *top,*base;

   int stacksize;

}stack;//为了方便说明,

 

void traverse(Node*T)

{

  stack s;

  s.top=-1;

  Node *r;

  r=T;

  while(top!=-1||r!=NULL)

  {

    s.top++;

    *s.top=r;

    while(r.lchild!=NULL){//检查r节点是否有左孩子,有则进栈

      s.top++;

      *s.top=r.lchild;

      r=r.lchild;

    }

    r=*s.top;//出栈

    s.top--;

 

//检查r是否为叶节点

    if(r.lchild==NULL)

    {//r为叶节点

      r.select=r.data;

      r.unsel=0;

    }

    else

    {//r不是叶节点,若以r为根节点,则还要考虑孩子和其兄弟的喜欢程度

      r.select=r.data+sum(j.unsel);//j为r的孩子

      r.unsel=sum(max{j.unsel,j.select});

    }

    r=r.rightsibling;//指向r节点的右兄弟

  }

}

 

其次是找出名单。

void find_the_list(Node*T){

   Node *r,*s;

   r=T;

   if(r==NULL) return;

   else if(r.parent==NULL){//表示是根节点

   if(r.select>r.unsel) r.go=1;//表示选择参加

   else r.go=0;//表示不参加

  }

  else{

    if(r.parent.go=1) r.go=0;

    else//当前节点的直接上司不会参加,即当前节点可以选择参加或者不参加,根据喜好程度和

      if(r.unsel<r.select) r.go=0;

      elser.go=1;

  }

   r=r.lchild;

   s=r.rsibling;

   find_the_list(r);

   find_the_list(s);

}

最后输出go域为1的节点,即公司的聚会名单,算法时间为O(2n),n为节点数。

 

 



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值