P1352 没有上司的舞会
题目描述:
题解思路:
首先题目中发明确告诉了是一棵树,所以在输入数据后应该构建一棵树来储存这些数据。
这是一道非常经典的树形dp问题,对每个结点dp[i][0]表示不邀请这个员工,其子树达到的最大快乐值,dp[i][1]表示邀请i员工其子树达到的最大值,对于每个结点的状态应该从这两方面去考虑。
dp[i][0]=(i的全部员工的max(dp[u][1],dp[u][0)相加,也就是其子员工来或不来的最大快乐值。
dp[i][1]=(i的全部员工的dp[u][0相加,也就是其子员工都不能不来的最大快乐值。
从根结点开始dp,最终结果就是max(dp[root][0],dp[root][1])
题目代码
#include<iostream> #include<algorithm> using namespace std; #define INF 1000000 int n=0; int root=-1; int r[6005]; int p[6005]={0}; //专门用于找根节点 int flag[6005]={0}; //flag[i]判断结点i是否参加聚会 int dp[6005][2]; struct node{ //树的结点 int size; int c[200]; //保存子节点的编号 c数组要开的大一点 防止不够 }; node dd[6000]; void dfs(int i){ dp[i][1]=r[i]; //i参加聚会 把自己的快乐值先加上
for(int j=0;j<dd[i].size;j++){ int son=dd[i].c[j]; //找i的孩子 if(son>0){ dfs(son); dp[i][0]+=max(dp[son][0],dp[son][1]); //若i不参加聚会,则i的孩子们有两种选择 dp[i][1]+=dp[son][0]; //i参加聚会 则i的孩子无法参加 } } } int main(){ cin>>n; for(int i=1;i<=n;i++){ cin>>r[i]; } for(int i=1;i<=n-1;i++){ //用结构体数组来存树 int a,b; cin>>a>>b; //b是上司 dd[b].c[dd[b].size++]=a; p[a]=1; //代表a不是根 } for(int i=1;i<=n;i++){ if(p[i]==0){ root=i; //找到根节点 break; } } for(int i=1;i<=n;i++){ dp[i][0]=0; dp[i][1]=0; } dfs(root); cout<<max(dp[root][0],dp[root][1]);//注意dp[root][1]在dfs中已经加过r[root] return 0; }
关于树形dp的一些解析和题目: