公司内部结构关系是层次化的,即员工按主管–下属关系构成一棵树,根节点为公司主席。人事部按“宴会交际能力”给每个员工打分,分值为实数。
Stewart教授是一家公司总裁的顾问,这家公司正在计划一个公司的聚会。这个公司有一个层次式的结构;也就是,管理关系形成一颗以总裁为根的树。人事部门按每个员工喜欢聚会的程度来排名,排名是一个实数。为了使每个参加聚会者都喜欢这个聚会,总裁不希望一个雇员和她的直接上司同时参加。
Stewart教授面对一颗描述公司结构的树,使用了左孩子右兄弟描述法。树中每个节点除了包含指针,还包含雇员的名字以及雇员喜欢聚会的排名。描述一个算法,它生成一张客人列表,使得客人喜欢聚会的程度的总和最大。分析你的算法的执行时间。
动态规划原理:
1、重叠子问题:
该问题会对某个领导的下属反复求解。
2、最优子结构
公司聚会有最佳方案,构成最优子结构
状态转移函数:
$people(0)=sum max(confirm(i,0),confirm(i,1))$
$people(1)=likevalue+sum confirm(i,0)$
$result=max(confirm(root,0),confirm(root,1))$
邻接矩阵求解
company_party_array.h
#include <iostream>
#define MAXNUM 20
//使用有向图的邻接矩阵来表示
bool party_graph[MAXNUM][MAXNUM];
int solution[MAXNUM][2]; //用来存储解决方案,solution[i][0]表示不被选中
//solution[i][1]表示被选中
int likevalue[MAXNUM]; //表示对party的热衷程度
int how_many_member;
int id;
int how_many_branch,branch_id;
int max(int a,int b)
{
return a>b?a:b;
}
int confirm(int id,int status) //递归求解方案
{
int result;
if(solution[id][status]!=-1)
return solution[id][status];
if(status==0)
{
result=0;
//表示这个id不参加聚会
for(int i=0;i<how_many_member;i++) //遍历这个id的边,即邻接链表
{
if(party_graph[id][i])
result+=max(confirm(i,0),confirm(i,1));
}
solution[id][status]=result;
return result;
}
else
{
result=likevalue[id];
for(int i=0;i<how_many_member;i++)
{
if(party_graph[id][i])
result+=confirm(i,0);
}
solution[id][status]=result;
return result;
}
}
company_party_array.cpp
#include "company_party_array.h"
#include <string.h>
using namespace std;
int main()
{
//Initialize:对数组的值进行初始化
for(int i=0;i<MAXNUM;i++)
{
for(int j=0;j<2;j++)
solution[i][j]=-1;
}
cout<<"Input the number of members who join the party: "<<endl;
cin>>how_many_member;
cout<<"Input the like value of members: "<<endl;
for(int i=0;i<how_many_member;i++)
cin>>likevalue[i];
for(int i=0;i<how_many_member;i++)
{
cout<<"Input member id and how many branch it has: "<<endl;
cin>>id>>how_many_branch; //输入每个人的编号和下属的个数
cout<<"branch id: "<<endl;
for(int j=0;j<how_many_branch;j++)
{
cin>>branch_id; //输入下属员工的id
party_graph[id][branch_id]=true;
}
}
//初始化完成
int root=0;
int result=confirm(root,0);
memset(solution,-1,sizeof(solution));
//注意使用这种方法,对数组中的值进行赋值
result=max(result,confirm(root,1));
cout<<result<<endl;
return 0;
}
左孩子右兄弟树求解
用辅助队列完成
LinkQueue.h
#include <iostream>
#include <ctime>
#include <cmath>
#include "CSTree.h"
#include <stdlib.h>
using namespace std;
#define MAXSIZE 20 //存储空间初始分配量
bool visit(QNodePtr c)
{
cout<<c->data;
return true;
}
//构造一个空队列
int InitQueue(LinkQueue *Q)
{
Q->front=Q->rear=(QNodePtr)malloc(sizeof(QNode));
if(!Q->front)
{
cout<<"overfolow";
exit(OVERFLOW);
}
Q->front->next=NULL;
return true;
}
//销毁队列,完成之后Q->front==Q->rear==NULL,均为空指针
bool DestroyQueue(LinkQueue *Q)
{
while(Q->front)
{
Q->rear=Q->front->next;
free(Q->front);
Q->front=Q->rear;
}
return true;
}
//将Q清为空队列
bool ClearQueue(LinkQueue *Q)
{
QNodePtr p,q;
Q->rear=Q->front;
p=Q->front->next;
Q->front->next=NULL;
while(p)
{
q=p;
p=p->next;
free(q);
}
return true;
}
bool QueueEmpty(LinkQueue Q)
{
if(Q.front==Q.rear)
return true;
else
return false;
}
//求队列的长度
int QueueLength(LinkQueue Q)
{
int count=0;
QNodePtr p=Q.front;
while(Q.rear!=p)
{
count++;
p=p->next;
}
return count;
}
bool GetHead(LinkQueue Q,QElemType *element)
{
QNodePtr p;
if(Q.front==Q.rear)
return false;
p=Q.front->next;
*element=p->data;
return true;
}
//插入元素e为Q的新的队尾元素
bool Enqueue(LinkQueue *Q,QElemType element)
{
QNodePtr s=(QNodePtr)malloc(sizeof(QNode));
if(!s)
exit(OVERFLOW);
s->data=element;
s->next=NULL;
Q->rear->next=s;
Q->rear=s;
return true;
}
bool Dequeue(LinkQueue *Q,QElemType *element)
{
QNodePtr p;
if(Q->front==Q->rear)
return false;
p=Q->front->next; //将要删除的队头节点暂时存给p
*element=p->data;
//重置队头
Q->front->next=p->next;
if(Q->rear==p)
Q->rear=Q->front;
free(p);
return true;
}
bool QueueTraverse(LinkQueue Q)
{
QNodePtr p;
p=Q.front->next;
while(p)
{
visit(p);
p=p->next;
}
cout<<endl;
return true;
}
CSTree.h
#include <iostream>
#include <string.h>
#include <stdlib.h>
#define Wrong 'W'
using namespace std;
typedef int Elemtype;
typedef struct CSNode
{
Elemtype data;
int status;
struct CSNode *firstChild;
struct CSNode *nextsibling;
}CSNode,*CSTree;
typedef CSTree QElemType;
typedef struct QNode
{
QElemType data;
struct QNode *next;
}QNode,*QNodePtr;
typedef struct
{
QNodePtr front,rear;
//队头,队尾指针
}LinkQueue;
int InitQueue(LinkQueue *Q);
bool DestroyQueue(LinkQueue *Q);
bool visit(QNodePtr c);
bool ClearQueue(LinkQueue *Q);
bool QueueEmpty(LinkQueue Q);
int QueueLength(LinkQueue Q);
bool GetHead(LinkQueue Q,QElemType *element);
bool Enqueue(LinkQueue *Q,QElemType element);
bool Dequeue(LinkQueue *Q,QElemType *element);
bool QueueTraverse(LinkQueue Q);
int CreateTree(CSTree &T)
{
LinkQueue helpQueue;
InitQueue(&helpQueue);
int buffchild[10];
//用来存放孩子们的缓存
int child_num;
memset(buffchild,0,10);
cout<<"Input root of the tree: if empty,enter -1: "<<endl;
cin>>buffchild[0];
if(buffchild[0]!=-1)
{
T=(CSTree)malloc(sizeof(CSTree));
T->status=-1;
if(!T)
exit(OVERFLOW);
T->data=buffchild[0];
T->nextsibling=NULL;
Enqueue(&helpQueue,T); //根节点入队,只存储根节点
while(!QueueEmpty(helpQueue))
{
QElemType temp;
Dequeue(&helpQueue,&temp);
//根节点出队
cout<<"Input the child number of "<<temp->data<<" if child number is 0, please enter '0'"<<endl;
cin>>child_num;
cout<<"Input the data of child "<<temp->data<<" ,if has no child ,enter -1"<<endl;
for(int i=0;i<child_num;i++)
cin>>buffchild[i];
if(child_num!=0) //表示有孩子,根为temp
{
CSTree child_node;
child_node=(CSTree)malloc(sizeof(CSTree)); //开辟孩子节点空间
child_node->status=-1;
if(!child_node)
exit(OVERFLOW);
child_node->data=buffchild[0];
//建立此时的根temp和child_node的孩子关系
temp->firstChild=child_node;
Enqueue(&helpQueue,child_node); //第一个孩子入队
CSTree child_ptr=child_node;
for(size_t i=1;i<child_num;i++)
{
child_node=(CSTree)malloc(sizeof(CSTree));
child_node->status=-1;
if(!child_node)
exit(OVERFLOW);
child_node->data=buffchild[i];
child_ptr->nextsibling=child_node;
Enqueue(&helpQueue,child_node);
child_ptr=child_node; //指向刚入队的孩子
}
child_ptr->nextsibling=NULL;
}
else
{
temp->firstChild=NULL;
}
}
}
else
{
T=NULL;
}
return true;
}
void DestroyTree(CSTree &T)
{
if(T) //树非空
{
if(T->firstChild)
DestroyTree(T->firstChild);
if(T->nextsibling)
DestroyTree(T->nextsibling);
free(T);
T=NULL;
}
}
void ClearTree(CSTree &T)
{
DestroyTree(T);
}
bool TreeEmpty(CSTree &T)
{
if(T)
return true;
else
return false;
}
int TreeDepth(CSTree &T)
{
if(!T)
return 0;
if(!T->firstChild)
return 1;
CSTree child_ptr;
int depth,max=0;
for(child_ptr=T->firstChild;child_ptr;child_ptr=child_ptr->nextsibling)
{
depth=TreeDepth(child_ptr);
if(depth>max)
max=depth;
}
return max+1;
}
Elemtype Root(CSTree &T)
{
if(T)
return T->data;
return 0;
}
CSNode* FindNode(CSTree &T,Elemtype cur_node)
{
LinkQueue Q;
InitQueue(&Q); //构造一个空队列
if(T)
{
Enqueue(&Q,T); //根节点入队
while(!QueueEmpty(Q))
{
QElemType tmp_node;
Dequeue(&Q,&tmp_node);
if(tmp_node->data==cur_node)
return tmp_node;
if(tmp_node->firstChild)
Enqueue(&Q,tmp_node->firstChild);
if(tmp_node->nextsibling)
Enqueue(&Q,tmp_node->nextsibling);
}
}
return NULL;
}
bool Assign(CSTree &T,Elemtype cur_node,Elemtype value) //进行赋值操作
{
if(!T) //树是空的
return false;
CSNode *find_cur_node=FindNode(T,cur_node);
if(!find_cur_node)
return false;
find_cur_node->data=value;
return true;
}
CSNode* Parent(CSTree &T,Elemtype cur_value)
{
LinkQueue Q;
InitQueue(&Q);
if(T)
{
if(T->data==cur_value)
return NULL; //根节点无双亲
Enqueue(&Q,T);
while(!QueueEmpty(Q))
{
QElemType cur_node;
Dequeue(&Q,&cur_node); //当前节点可能作为根节点,为cur_node
QElemType parent_ptr=cur_node; //提示刚出队的元素
if(cur_node->firstChild)
{
if(cur_node->firstChild->data==cur_value)
return parent_ptr;
Enqueue(&Q,cur_node->firstChild);
QElemType brotherPtr=cur_node->firstChild->nextsibling;
//指向孩子的兄弟节点
while(brotherPtr)
{
if(brotherPtr->data==cur_value)
return parent_ptr;
Enqueue(&Q,brotherPtr);
brotherPtr=brotherPtr->nextsibling;
}
}
}
}
return NULL;
}
Elemtype Leftchild(CSTree &T,Elemtype cur_node)
{
CSNode* node;
node=FindNode(T,cur_node);
if(node)
{
if(node->firstChild)
return node->firstChild->data;
}
return Wrong;
}
Elemtype Rightsibling(CSTree &T,Elemtype cur_node)
{
CSNode* node;
node=FindNode(T,cur_node);
if(node)
{
if(node->nextsibling)
{
return node->nextsibling->data;
}
}
return Wrong;
}
bool LevelOrderTraverse(CSTree &T)
{
//层序遍历
LinkQueue Q;
InitQueue(&Q);
if(T)
{
cout<<T->data<<" ";
Enqueue(&Q,T); //根节点排队
while(!QueueEmpty(Q))
{
QElemType cur_node,child_node;
Dequeue(&Q,&cur_node); //当前根节点出队
child_node=cur_node->firstChild;
while(child_node)
{
cout<<child_node->data<<" ";
Enqueue(&Q,child_node);
child_node=child_node->nextsibling;
}
}
return true;
}
return false;
}
bool recurse_Traverse(CSTree &T)
{
if(T)
{
T->status=-1;
cout<<T->data<<" "<<T->status<<" ";
recurse_Traverse(T->firstChild);
recurse_Traverse(T->nextsibling);
}
}
void refresh_tree(CSTree &T)
{
if(T)
{
T->status=-1;
refresh_tree(T->firstChild);
refresh_tree(T->nextsibling);
}
}
bool recurse_CreateTree(CSTree &T)
{
int child_number;
cout<<"Input the child number of "<<T->data<<" if it has no child, input 0"<<endl;
cin>>child_number;
if(child_number==0)
{
T->firstChild=NULL;
return true;
}
else
{
CSTree child,ptr;
int child_data;
child=(CSTree)malloc(sizeof(CSTree));
child->status=-1;
cout<<"Input the data of the child node: "<<endl;
cin>>child_data;
child->data=child_data;
T->firstChild=child;
ptr=child;
for(int i=1;i<child_number;i++)
{
CSTree brother;
int brother_data;
brother=(CSTree)malloc(sizeof(CSTree));
brother->status=-1;
cout<<"Input the data of the child node: "<<endl;
cin>>brother_data;
brother->data=brother_data;
ptr->nextsibling=brother;
ptr=ptr->nextsibling;
}
ptr->nextsibling=NULL;
for(CSTree p=T->firstChild;p;p=p->nextsibling)
{
recurse_CreateTree(p);
}
return true;
}
}
bool depth_traverse(CSTree &T)
{
if(T)
{
T->status=-1;
cout<<T->data<<" "<<T->status<<" ";
for(CSTree p=T->firstChild;p;p=p->nextsibling)
depth_traverse(p);
}
}
company_party.cpp
#include "LinkQueue.h"
int max(int a,int b)
{
return a>b?a:b;
}
int confirm(CSTree &T,int flag)
{
int result;
if(T->status!=-1)
return T->status;
if(flag==1)
{
result=T->data;
for(CSTree p=T->firstChild;p!=NULL;p=p->nextsibling)
{
result+=confirm(p,0);
}
T->status=result;
return result;
}
else
{
result=0;
int maxnum;
for(CSTree p=T->firstChild;p;p=p->nextsibling)
{
maxnum=confirm(p,0);
refresh_tree(p); //注意在求max的时候,洗刷status的值
maxnum=max(maxnum,confirm(p,1));
result+=maxnum;
}
T->status=result;
return result;
}
}
int main()
{
CSTree T;
CreateTree(T);
cout<<"Level order Traverse: "<<endl;
LevelOrderTraverse(T);
cout<<endl;
recurse_Traverse(T);
cout<<endl;
int result=confirm(T,1);
cout<<result<<endl;
refresh_tree(T);
cout<<endl;
result=max(result,confirm(T,0));
cout<<result;
cout<<endl;
cout<<"recurse mathod:"<<endl;
CSTree Recur_T;
int root_data;
Recur_T=(CSTree)malloc(sizeof(CSTree));
Recur_T->status=-1;
cout<<"Input the data of root : "<<endl;
cin>>root_data;
Recur_T->data=root_data;
recurse_CreateTree(Recur_T);
cout<<"Level order Traverse: "<<endl;
LevelOrderTraverse(Recur_T);
cout<<endl;
depth_traverse(Recur_T);
cout<<endl;
}
递归版本
CSTree.h
#include <iostream>
#include <string.h>
#include <stdlib.h>
#define Wrong 'W'
using namespace std;
typedef int Elemtype;
typedef struct CSNode
{
Elemtype data;
int status;
struct CSNode *firstChild;
struct CSNode *nextsibling;
}CSNode,*CSTree;
bool recurse_CreateTree(CSTree &T)
{
int child_number;
cout<<"Input the child number of "<<T->data<<" if it has no child, input 0"<<endl;
cin>>child_number;
if(child_number==0)
{
T->firstChild=NULL;
return true;
}
else
{
CSTree child,ptr;
int child_data;
child=(CSTree)malloc(sizeof(CSTree));
child->status=-1;
cout<<"Input the data of the child node: "<<endl;
cin>>child_data;
child->data=child_data;
T->firstChild=child;
ptr=child;
for(int i=1;i<child_number;i++)
{
CSTree brother;
int brother_data;
brother=(CSTree)malloc(sizeof(CSTree));
brother->status=-1;
cout<<"Input the data of the child node: "<<endl;
cin>>brother_data;
brother->data=brother_data;
ptr->nextsibling=brother;
ptr=ptr->nextsibling;
}
ptr->nextsibling=NULL;
for(CSTree p=T->firstChild;p;p=p->nextsibling)
{
recurse_CreateTree(p);
}
return true;
}
}
bool depth_traverse(CSTree &T)
{
if(T)
{
T->status=-1;
cout<<T->data<<" "<<T->status<<" ";
for(CSTree p=T->firstChild;p;p=p->nextsibling)
depth_traverse(p);
}
}
company_party.cpp
#include "CSTree.h"
int max(int a,int b)
{
return a>b?a:b;
}
int confirm(CSTree &T,int flag)
{
int result;
if(T->status!=-1)
return T->status;
if(flag==1)
{
result=T->data;
for(CSTree p=T->firstChild;p!=NULL;p=p->nextsibling)
{
result+=confirm(p,0);
}
T->status=result;
return result;
}
else
{
result=0;
int maxnum;
for(CSTree p=T->firstChild;p;p=p->nextsibling)
{
maxnum=confirm(p,0);
refresh_tree(p); //注意在求max的时候,洗刷status的值
maxnum=max(maxnum,confirm(p,1));
result+=maxnum;
}
T->status=result;
return result;
}
}
int main()
{
cout<<"recurse mathod:"<<endl;
CSTree Recur_T;
int root_data;
Recur_T=(CSTree)malloc(sizeof(CSTree));
Recur_T->status=-1;
cout<<"Input the data of root : "<<endl;
cin>>root_data;
Recur_T->data=root_data;
recurse_CreateTree(Recur_T);
cout<<"Level order Traverse: "<<endl;
LevelOrderTraverse(Recur_T);
cout<<endl;
depth_traverse(Recur_T);
cout<<endl;
}
实现结果
非递归算法:
递归算法:
仅用于测试:
特别注意:在用树实现递归的时候,算完一次confirm()之后,要使用refresh_tree把树刷新一遍,去掉第一次计算的痕迹
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。