1 条题解
-
0
算法思路:树形动态规划(DP)
关键思想
- 树形DP:由于组织结构是树形结构,可以通过动态规划递归地计算每个节点的两种状态:
- 选当前节点:不能选其直接子节点(上司和员工不能同时选)。
- 不选当前节点:可以选择或不选其子节点(需比较子节点的选与不选的最优解)。
- 唯一性判断:在动态规划过程中,同时记录当前状态的解是否唯一。
状态定义
对每个节点
u
,定义:dp[u][0]
:不选u
时的最大人数。dp[u][1]
:选u
时的最大人数。sole[u][0]
:不选u
时的解是否唯一。sole[u][1]
:选u
时的解是否唯一。
状态转移
- 选
u
:- 人数:
dp[u][1] = 1 + sum(dp[v][0])
(v
是u
的子节点)。 - 唯一性:若任意子节点
v
的dp[v][0]
不唯一,则dp[u][1]
不唯一。
- 人数:
- 不选
u
:- 人数:
dp[u][0] = sum(max(dp[v][0], dp[v][1]))
。 - 唯一性:
- 若
dp[v][0] == dp[v][1]
,则解不唯一。 - 若选择较大值的解不唯一,则
dp[u][0]
不唯一。
- 若
- 人数:
算法步骤
- 建树:用邻接表存储员工-上司关系。
- 动态规划:从根节点(大老板)开始递归计算每个节点的
dp
和sole
。 - 输出结果:比较根节点的选与不选,输出最大值及其唯一性。
代码实现(C++)
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int head[210]; char name1[110],name2[110]; char name[210][110]; int cnt,len; int max(int a,int b) { return a>b?a:b;} class node { public: int v,yes,no; bool yessole,nosole; bool tt; bool vis; int next; node() { tt=true;vis=false; yes=1;no=0; yessole=true;nosole=true; } }; int research(char a[]) { for(int i=1;i<=cnt;i++) if(strcmp(a,name[i])==0) return i; cnt++; strcpy(name[cnt],a); return cnt; } void add(int son,int father,node g[]) { g[++len].v =son; g[len].tt=false; g[len].next =head[father]; head[father]=len; } void DP(int root,node g[]) { g[root].vis =true; int i,r1=0,r0; for(i=head[root];i;i=g[i].next ) { int v=g[i].v ; if(!g[v].vis) DP(v,g); r1+=g[v].no ; if(g[v].nosole ==false) g[root].yessole =false; g[root].no +=max(g[v].yes ,g[v].no ); if(g[v].yes ==g[v].no ||(g[v].no>g[v].yes &&g[v].nosole ==false)||(g[v].yes >g[v].no &&g[v].yessole ==false)) g[root].nosole =false; } g[root].yes =r1+1; } int main() { int n; while(1) { cin>>n; if(n==0) break; cnt=1; len=0; node g[10005]; memset(head,0,sizeof(head)); scanf("%s",&name1); strcpy(name[1] ,name1 ); for(int i=1;i<n;i++) { scanf("%s%s",&name1,&name2); int f1=research(name1); int f2=research(name2); add(f1,f2,g); } DP(1,g); if(g[1].no >g[1].yes ) { printf("%d ",g[1].no ); if(g[1].nosole ) printf("Yes/n"); else printf("No/n"); } else if(g[1].no ==g[1].yes ){ printf("%d No/n",g[1].yes ); } else { printf("%d ",g[1].yes ); if(g[1].yessole ) printf("Yes/n"); else printf("No/n"); } } return 0; }
- 树形DP:由于组织结构是树形结构,可以通过动态规划递归地计算每个节点的两种状态:
- 1
信息
- ID
- 2343
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 6
- 标签
- 递交数
- 2
- 已通过
- 1
- 上传者