动态规划:P1352没有上司的舞会
没有上司的舞会
题目:
思路:
可以学习像区间dp里面,分左右端点dpdp一样,构建二维DP数组,第二维代表有没有连下一个结点,0代表连了下一个结点,1代表没有连,所以我们初始化所有叶子结点的dp[叶子][0]等于叶子的快乐指数,然后从根往下dfs,因为一开始不知道根,和叶子,可以计算出度和入度,然后遍历找到入度为0的点就是根开始dfs,搜到最底层,如果出度为0就是叶子,初始化叶子结点的dp[叶子][0]等于他的快乐指数,否则定义sum1来计算要自己这个结点 sum2来计算不要自己这个结点,显然要自己这个结点就不能要下一个节点了,所以sum1就要加上所有邻接点的dp[邻接点][1],sum2就是0了 。这里注意两个问题 ①:快乐指数可以能是负数,所以sum并不是加上所有邻接点的dp 而是加上每一个邻接点的max(dp,0),如果小于0就不加了。②:初始化问题:sum2初始化为0 不要这个结点,sum1并不是初始化为这个结点的快乐指数,而是初始化为max(0,happy[this]),为什么呢,因为自己这个点的快乐指数小于0还不如不要自己这个点,也不影响别的点的计算,如果少了这行代码就只有90分。
关键DP代码:
最优ans就是遍历以每一个结点为起始的1 和 0 要遍历。
遍历代码:
计算入度和出度及邻接矩阵的构建:
总AC代码:
1 #include<iostream> 2 #include<algorithm> 3 #include<vector> 4 using namespace std; 5 const int maxn = 6 * 1e3 + 5; 6 vector<int>c[maxn];//邻接矩阵 7 int happy[maxn]; 8 int dp[maxn][2]; 9 int in[maxn]; 10 int out[maxn]; 11 void dfs(int u) 12 { 13 if (!out[u]) 14 { 15 dp[u][0] = happy[u]; 16 return; 17 } 18 int sum1 =max( happy[u],0);//如果自己的快乐指数是负的 就直接不邀请自己 也不影响邀请其他的 19 int sum2 = 0; 20 for (int i = 0; i < c[u].size(); ++i) 21 { 22 dfs(c[u][i]); 23 sum1 += max(0,dp[c[u][i]][1]);//如果子树的快乐指数和小于0 就不邀请这个子树的了 24 sum2 += max(0, dp[c[u][i]][0]);//如果子树的快乐指数和小于0 就不邀请这个子树的了 25 } 26 dp[u][0] = sum1; 27 dp[u][1] = sum2; 28 //cout << dp[u][0] << endl; 29 //cout << dp[u][1] << endl; 30 } 31 int n, a, b; 32 int main() 33 { 34 cin >> n; 35 for (int i = 1; i <= n; ++i) 36 cin >> happy[i]; 37 for (int i = 1; i < n; ++i)//邻接矩阵的构建 38 { 39 cin >> a >> b;//有向边 b->a 40 c[b].push_back(a); 41 in[a]++;//入度和出度很重要! 42 //cout <<"in" << a << in[a] << endl; 43 out[b]++; 44 //cout << "out" << b << out[b] << endl; 45 } 46 int root; 47 for (int i = 1; i <= n; ++i) 48 { 49 if (!in[i]) 50 { 51 root = i; 52 break; 53 } 54 } 55 dfs(root); 56 int ans = -0x7fffffff; 57 for (int i = 1; i <= n; ++i) 58 { 59 ans = max(ans, max(dp[i][0], dp[i][1])); 60 } 61 cout << ans; 62 return 0; 63 }
通过图: