1

公司内部结构关系是层次化的,即员工按主管–下属关系构成一棵树,根节点为公司主席。人事部按“宴会交际能力”给每个员工打分,分值为实数。
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把树刷新一遍,去掉第一次计算的痕迹


fogsail
31 声望6 粉丝

一直认为数学、音乐、诗歌都是世间最美好的语言,程序是用数学这种语言写成的逻辑。于2014年12月被人拉到兰州大学开源社区中去(mirror.lzu.edu.cn),从此与自由软件和编程解下不解之缘,毅然抛弃生物专业从事编...


引用和评论

0 条评论