链接:http://acm.hdu.edu.cn/showproblem.php?pid=1520
题意:给出一个职场关系图,每一个人有自己的价值,而且每一个人仅仅有一个领导,我要邀请的人不能够是一个人和他的直系领导,问最多能邀请到多少价值的人。
思路:入门题,就是把简单DP运用到了树这样的数据结构里,蛮有趣的。看题意应该叫森林DP比較合适一点。首先是建树,找到的根节点就是没有父亲节点的节点。对于树上的一个节点u,dp[u][0]代表着不选择这个节点能得到的最大价值,dp[u][1]代表着选择这个节点能得到的最大价值。
状态转移方程:dp[u][0]=sum(max(dp[v][0],dp[v][1]))。不选当前节点,那么他的每一个子节点都是能够选也能够不选。
dp[u][1]=sum(dp[v][0])。选择当前节点,那么他的每一个子节点都不能够选择。
代码:
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<map> #include<queue> #include<stack> #include<vector> #include<ctype.h> #include<algorithm> #include<string> #define PI acos(-1.0) #define maxn 6005 #define INF 0x7fffffff typedef long long LL; using namespace std; int score[maxn],head[maxn],top,dp[maxn][2]; bool from[maxn]; void init() { memset(head,-1,sizeof(head)); memset(from,0,sizeof(from)); memset(dp,0,sizeof(dp)); top=0; } struct Edge { int v; int next; } edge[maxn]; int add_edge(int u,int v) { edge[top].v=v; edge[top].next=head[u]; head[u]=top++; } void dfs(int u) { for(int i=head[u]; i!=-1; i=edge[i].next) { int v=edge[i].v; dfs(v); dp[u][1]+=dp[v][0]; dp[u][0]+=max(dp[v][1],dp[v][0]); } dp[u][1]+=score[u]; } int main() { int tot,u,v; while(~scanf("%d",&tot)) { init(); for(int i=1; i<=tot; i++) scanf("%d",&score[i]); while(scanf("%d%d",&u,&v)) { if(u==0&&v==0) break; add_edge(v,u); from[u]=true; } for(int i=1; i<=tot; i++) { if(!from[i]) dfs(i); } int ans=0; for(int i=1; i<=tot; i++) { if(from[i]==0) ans+=max(dp[i][0],dp[i][1]); } printf("%d ",ans); } return 0; }