ACM:计划一个公司聚会 (大一时头疼…

 计划一个公司聚会

问题描述:

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

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

        要求你算出最大的喜欢程度和。

Sample Input:

      n: 员工个数, 接下一行输入每个员工对这次party的喜欢程度.

      接下的n行内, 每行输入u:员工编号, num: 该员工下属的个数, vi: 该员工的第i个下属的编号(0<=i<n)

 

Sample Output:

      输出最大的喜欢程度和.

 

Sample Input:

5
2 3 5 4 4
0 2 2 3
2 1 1
1 1 4
3 0
4 0

6
20 3 5 4 5 30
0 2 2 3
2 1 1
3 1 4
1 0
4 1 5
5 0

 

Sample Output:

13

53

 

题意: 上述中文描述

 

解题思路:

        1. 每个员工可以设置2个状态state: 参加和不参加.

        2. 动态规划求解, 设状态: dp[node][0]: node员工不参加party的及其下属的最大喜欢程度.

                                 dp[node][1]: node员工参加party的及其下属的最大喜欢程度.

        3. 状态转移方程:

                     dp[node][0] = max(DP(i,0),DP(i,1)); (i是node的直接下属编号)

                     dp[node][1] = a[node]+∑DP(i,0); (a[node]: node员工对聚会的喜欢程度);

              4. 最后结果是: result = max(DP(root,0) , DP(root,1));

                 因为root没有上司所以要分别求2次, 最后取较大值.

 

代码:

#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
#define MAX 105

int n; //员工数量
bool g[MAX][MAX]; //保存员工树状关系
int a[MAX]; //对party的喜欢程度
int root; //无上司的人 (boss)
int dp[MAX][2]; //dp[i][0]: node不参加; dp[i][1]: 参加

inline int max(int a,int b)
{
 return a > b ? a : b;
}

void read_graph()
{
 int i, j;
 memset(g,false,sizeof(g));
 memset(dp,-1,sizeof(dp));
 for(i = 0; i < n; ++i)
  scanf("%d",&a[i]); //每个人对party的喜欢程度

 int u, v;
 int num;
 for(i = 0; i < n; ++i)
 {
  scanf("%d %d",&u,&num); //每个人得编号和下属个数
  for(j = 0; j < num; ++j)
  {
   scanf("%d",&v); //下属编号
   g[u][v] = true;
  }
 }
 root = 0;
}

int DP(int node, int state) //当前节点node, state: 是否参加party
{
 if(dp[node][state] != -1) return dp[node][state];
 int ans;
 if(state == 0) //node不参加party
 {
  ans = 0;
  for(int i = 0; i < n; ++i)
  {
   if(g[node][i])
    ans += max(DP(i,0),DP(i,1));
  }
  dp[node][state] = ans;
  return ans;
 }
 else //node参加party
 {
  ans = a[node];
  for(int i = 0; i < n; ++i)
  {
   if(g[node][i])
    ans += DP(i,0);
  }
  dp[node][state] = ans;
  return ans;
 }
 
}

int main()
{
 freopen("input.txt","r",stdin);
 while(scanf("%d",&n) != EOF)
 {
  read_graph();
  int result = DP(root,0); //分别算出root节点是否参加party
  memset(dp,-1,sizeof(dp));
  result = max(result, DP(root,1));
  cout << result << endl;
 }

 return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值