题意:
某人要开一个聚会,每个人都有一个自己的交际评分,但是他们都不想和自己的直接上司在一起,那样会不开心,所以只让一部分人来,希望你能找出评分最大的方案。
解析:
关于上司下级的事情,就会涉及一点并查集,不过这题和并查集没有太大关系,需要建树来维系他们之间的关系,然后用树状dp来写,状态转移方程式为dp[i][0]+=max(dp[j][1],dp[i][0]),dp[i][1]+=dp[j][0];i表示父节点,j为子节点,0的意思是i或j没有出席m,1表示i或j出席了,也就是如果父节点没有出席,子节点可以出席也可以不出席,如果父节点出席了,子节点一定不能出席。
代码:
#include <iostream> #include <stdio.h> #include <string.h> #include <math.h> #include <algorithm> #include <queue> #include <vector> using namespace std; #define N 6005 #define oo 0x3f3f3f3f vector<int>G[N]; int n,dp[N][2],father[N]; void dfs(int root) { for(int i=0;i<G[root].size();i++) { dfs(G[root][i]); } for(int i=0;i<G[root].size();i++) { dp[root][0]+=max(dp[G[root][i]][0],dp[G[root][i]][1]); dp[root][1]+=dp[G[root][i]][0]; } } int main() { int u,v; while(~scanf("%d",&n)) { memset(father,-1,sizeof(father)); memset(dp,0,sizeof(dp)); for(int i=1;i<=n;i++) { scanf("%d",&dp[i][1]); G[i].clear(); } while(scanf("%d%d",&u,&v)&&(u+v)) { father[u]=v; G[v].push_back(u); } int root=1; while(father[root]!=-1) root=father[root]; dfs(root); printf("%d ",max(dp[root][1],dp[root][0])); } }