Description
Input
Output
Sample Input
7 1 1 1 1 1 1 1 1 3 2 3 6 4 7 4 4 5 3 5 0 0
Sample Output
5
题目大意:
学校要举办周年纪念日,每个人都有一个欢乐度,但是见到自己的直接上司的时候瞬间就不欢乐了,So,上司去我不去,上司不去我再去,这样才能愉快的玩耍,然后求最大的欢乐度。
解题思路:
给出一个关系图,把它转化成一个树(小白书上面有,无根树转有根树),然后求出递推方程
dp[i][0] += max(dp[j][0] , dp[j][1]); i为上司,j为下级 dp[ i ][ 1 ] += dp[ j ][ 0 ]; dp[i][0]表示i不去,dp[i][1]表示i去。
一次遍历求最优解就可以了。
代码如下:
#include<iostream> #include<cstdio> #include<map> #include<math.h> #include<cstring> #include<vector> #include<algorithm> using namespace std; int pre[6010]; vector<int> G[6010]; // 动态存储邻接矩阵 int dp[6010][2], vis[6010], n; void dfs(int u, int father) { int d = G[u].size(); for(int i = 0; i < d; i++) { int v = G[u][i]; if(v != father) { dfs(v, pre[v] = u); } } } void d(int t) { vis[t] = 1;// 标记已被访问 for(int i = 1; i <= n; i++) { if(pre[i] == t && !vis[i]) { d(i);//当遍历到叶子,求最优解 dp[t][0] += max(dp[i][0], dp[i][1]); dp[t][1] += dp[i][0]; } } } int main() { int i, u, v; while(scanf("%d",&n) != EOF) { memset(dp, 0, sizeof(dp)); for(i = 1; i <= n; i++) scanf("%d",&dp[i][1]); while(scanf("%d%d",&u,&v) && (u + v)) { G[u].push_back(v); G[v].push_back(u); } memset(pre, -1, sizeof(pre));//设置初始都指向-1位父亲结点 dfs(1,-1); memset(vis, 0, sizeof(vis)); d(1); printf("%d\n",max(dp[1][0], dp[1][1])); } return 0; }