没有上司的舞会(选择类树形DP)

传送门

题意:学校内有N个职员,编号为1~N.他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司.现在有个舞会,舞会每邀请来一个职员都会增加一定的快乐指数Ri,但是,如果某个职员的上司来参加舞会了,那么这个职员就无论如何也不肯来参加舞会了.求最大的快乐指数。

分析:一道经典的选择类树形DP问题.既然题目都直白地告诉了说具有树形关系,所以dfs从根节点层层递归下去把树构建出来.根节点当然就是校长了,即没有直接上司的人.设pd[i]表示i有无上司,则有pd[root]=0;

设f[x][0/1]分别表示x不参加/参加舞会的最大快乐指数.既然有两种状态,就有两种转移.

第一种情况:x不参加舞会,则x的下属y可能参加,也可能不参加.

f[x][0]=max(f[x][0],max(f[x][0]+f[y][1],f[x][0]+f[y][0]))

第二种情况:x参加舞会,则x的下属y不可能参加

f[x][1]=max(f[x][1],f[x][1]+f[y][0])

P.S.应该是数据太水,这样讨论就直接一遍过了,看了一下题解,每个人的转移都有一点差别...

int n,root;
int pd[6005],f[6005][2];
vector<int>q[6005];
//q[x]记录q的下属有哪些,相当于直接用vector存图了
void dfs(int x){
    for(int i=0;i<q[x].size();i++){
		int y=q[x][i];
		dfs(y);
		f[x][0]=max(f[x][0],max(f[x][0]+f[y][1],f[x][0]+f[y][0]));
		f[x][1]=max(f[x][1],f[x][1]+f[y][0]);
    }
    return;
}
int main(){
    n=read();
    for(int i=1;i<=n;i++)f[i][1]=read();
    for(int i=1;i<=n-1;i++){
		int a=read(),b=read();
		q[b].push_back(a);//a是b的下属之一
		pd[a]=1;
    }
    int a=read(),b=read();
//根据题意最后还会输出两个0,吞掉.
    for(int i=1;i<=n;i++){
		if(pd[i]==0){
	    	root=i;
	    	break;
		}
    }//找到根节点
    dfs(root);//从根节点开始dfs
    printf("%d\n",max(f[root][0],f[root][1]));
    return 0;
}

posted on 2019-02-13 15:59  PPXppx  阅读(128)  评论(0编辑  收藏  举报