[树形dp]Weight the Tree Codeforces1646D
You are given a tree of?nn?vertices numbered from?11?to?nn. A tree is a connected undirected graph without cycles.
For each?i=1,2,…,ni=1,2,…,n, let?wiwi?be the weight of the?ii-th vertex. A vertex is called?good?if its weight is equal to the sum of the weights of all its neighbors.
Initially, the weights of all nodes are unassigned. Assign positive integer weights to each vertex of the tree, such that the number of good vertices in the tree is maximized. If there are multiple ways to do it, you have to find one that minimizes the sum of weights of all vertices in the tree.
Input
The first line contains one integer?nn?(2≤n≤2?1052≤n≤2?105) — the number of vertices in the tree.
Then,?n?1n?1?lines follow. Each of them contains two integers?uu?and?vv?(1≤u,v≤n1≤u,v≤n) denoting an edge between vertices?uu?and?vv. It is guaranteed that the edges form a tree.
Output
In the first line print two integers ?— the maximum number of good vertices and the minimum possible sum of weights for that maximum.
In the second line print?nn?integers?w1,w2,…,wnw1,w2,…,wn?(1≤wi≤1091≤wi≤109) ?— the corresponding weight assigned to each vertex. It can be proven that there exists an optimal solution satisfying these constraints.
If there are multiple optimal solutions, you may print any.
Examples
input
4 1 2 2 3 2 4output
3 4 1 1 1 1input
3 1 2 1 3output
2 3 1 1 1input
2 1 2output
2 2 1 1input
9 3 4 7 6 2 1 8 3 5 6 1 8 8 6 9 6output
6 11 1 1 1 1 1 1 1 3 1題意:?給出一顆樹(shù),現(xiàn)在需要你為每個(gè)點(diǎn)分配權(quán)值,當(dāng)一個(gè)點(diǎn)權(quán)值等于其相鄰點(diǎn)權(quán)值和,那么該點(diǎn)被稱(chēng)為good點(diǎn),求在滿(mǎn)足good點(diǎn)最大的前提下樹(shù)上所有點(diǎn)權(quán)和最小的方案。
分析:?首先需要想到相鄰兩點(diǎn)不可能同時(shí)被記為good點(diǎn),這樣這道題目就有點(diǎn)像經(jīng)典樹(shù)形dp題——沒(méi)有上司的舞會(huì)了,設(shè)狀態(tài)dp[i][0/1]表示在以i為根的子樹(shù)中且i點(diǎn)不是good點(diǎn)/i點(diǎn)是good點(diǎn)的最大總good點(diǎn)數(shù),為了統(tǒng)計(jì)最終方案還需要記錄dp2[i][0/1],dp2[i][0/1]表示在以i為根的子樹(shù)中且i點(diǎn)不是good點(diǎn)/i點(diǎn)是good點(diǎn)的總權(quán)重最小值。
接下來(lái)考慮狀態(tài)轉(zhuǎn)移,如果當(dāng)前點(diǎn)是good點(diǎn)那么所有子節(jié)點(diǎn)都不能是good點(diǎn),所以dp[now][1] += dp[son][0],dp2[now][1] += dp2[son][0],如果當(dāng)前點(diǎn)不是good點(diǎn)那么子結(jié)點(diǎn)可以是good點(diǎn)也可以不是good點(diǎn),具體哪種情況取決于dp值和dp2值,如果dp[son][0] > dp[son][1],那么dp[now][0] += dp[son][0],dp2[now][0] += dp2[son][0],如果dp[son][0] <?dp[son][1],那么dp[now][0] += dp[son][1],dp2[now][0] += dp2[son][1],如果dp[son][0] ==?dp[son][1],此時(shí)dp[now][0]?+= dp[son][0],畢竟都一樣大,加哪個(gè)都一樣,不過(guò)這時(shí)候dp2[now][0]就需要加小的那個(gè)了,在這種情況下如果dp2[son][0] <?dp2[son][1],那么dp2[now][0] += dp2[son][0],否則dp2[now][0] += dp2[son][1]。
狀態(tài)初始化就是對(duì)于葉子結(jié)點(diǎn)now,令dp[now][1] = 1, dp[now][0] = 0, dp2[now][1] = (點(diǎn)now相鄰點(diǎn)個(gè)數(shù)), dp2[now][0] = 0,然后先dfs到樹(shù)的最底層,回溯的過(guò)程中用子結(jié)點(diǎn)信息更新當(dāng)前點(diǎn)信息。
求出dp數(shù)組和dp2數(shù)組后就可以開(kāi)始構(gòu)造方案了,這個(gè)過(guò)程其實(shí)和狀態(tài)轉(zhuǎn)移的思想類(lèi)似。設(shè)一個(gè)布爾數(shù)組st[i][0/1],st[i][0]表示在根節(jié)點(diǎn)不是good點(diǎn)的情況下i號(hào)點(diǎn)是否為good點(diǎn),st[i][1]表示在根節(jié)點(diǎn)是good點(diǎn)的情況下i號(hào)點(diǎn)是否為good點(diǎn)。根據(jù)根節(jié)點(diǎn)是否為good點(diǎn)分為兩種情況,這兩種情況下的最優(yōu)方案都需要求解。具體過(guò)程其實(shí)也是一個(gè)dfs,以根節(jié)點(diǎn)為good點(diǎn)這種情況舉例,此時(shí)先初始化st[1][1] = true,然后進(jìn)入dfs,對(duì)于每個(gè)點(diǎn)都需要看其父節(jié)點(diǎn)的狀態(tài),如果st[fa][1] == true,那么當(dāng)前點(diǎn)狀態(tài)直接已知,肯定是st[now][1] = false,如果st[fa][1] = false,那么當(dāng)前點(diǎn)可good也可不good,如果dp[now][1] > dp[now][0],那么st[now][1]就應(yīng)該取good點(diǎn)更優(yōu),st[now][1] = true,如果dp[now][1] <?dp[now][0],那么st[now][1]不取good點(diǎn)更優(yōu),st[now][1] = false,如果dp[now][1] ==?dp[now][0],再看dp2[now][1]和dp2[now][0],如果dp2[now][1] <?dp2[now][0],st[now][1] = true,否則st[now][1] = false,對(duì)于根節(jié)點(diǎn)不為good點(diǎn)的情況也是一樣的,只不過(guò)初始化st[1][0] = false。
最后特判一下n == 2的情況,因此此時(shí)不符合前面說(shuō)的相鄰兩點(diǎn)間只有一個(gè)點(diǎn)能是good點(diǎn)。
具體代碼如下:
#include <iostream> #include <cstdio> #include <algorithm> #include <string> #include <cstring> #include <vector> #define int long long using namespace std;int dp[200005][2], s[2], dp2[200005][2]; bool st[200005][2]; vector<int> to[200005];void dfs(int now, int fa){for(int i = 0; i < to[now].size(); i++){int v = to[now][i];if(v == fa) continue;dfs(v, now);}dp[now][1] = 1, dp[now][0] = 0;dp2[now][1] = to[now].size(), dp2[now][0] = 0;int mx = 0;for(int i = 0; i < to[now].size(); i++){int v = to[now][i];if(v == fa) continue;if(dp[v][1] > dp[v][0]){mx += dp[v][1];dp2[now][0] += dp2[v][1];}else if(dp[v][0] > dp[v][1]){mx += dp[v][0];dp2[now][0] += dp2[v][0];}else{mx += dp[v][0];dp2[now][0] += min(dp2[v][0], dp2[v][1]);}dp[now][1] += dp[v][0];dp2[now][1] += dp2[v][0];}dp[now][0] += mx; }void dfs2(int now, int fa, int type){if(fa != 0){if(st[fa][type] == 1) st[now][type] = 0;else if(dp[now][0] > dp[now][1])st[now][type] = 0;else if(dp[now][1] > dp[now][0])st[now][type] = 1;else if(dp2[now][0] > dp2[now][1])st[now][type] = 1; elsest[now][type] = 0;}for(int i = 0; i < to[now].size(); i++){int v = to[now][i];if(v == fa) continue;dfs2(v, now, type);} }signed main() {int n;cin >> n;for(int i = 1; i < n; i++){int u, v;scanf("%lld%lld", &u, &v);to[u].push_back(v);to[v].push_back(u);}if(n == 2){puts("2 2\n1 1");return 0;}dfs(1, 0);printf("%lld ", max(dp[1][0], dp[1][1]));s[0] = s[1] = 0;//1無(wú)貢獻(xiàn)時(shí)權(quán)值和 st[1][0] = 0;dfs2(1, 0, 0);//1有貢獻(xiàn)時(shí)權(quán)值和st[1][1] = 1;dfs2(1, 0, 1);for(int i = 1; i <= n; i++){if(st[i][0]) s[0] += to[i].size();else s[0]++;}for(int i = 1; i <= n; i++){if(st[i][1]) s[1] += to[i].size();else s[1]++; }if(dp[1][0] > dp[1][1]){printf("%lld\n", s[0]);for(int i = 1; i <= n; i++){if(st[i][0]) printf("%lld ", to[i].size());else printf("1 ");}}else if(dp[1][0] < dp[1][1]){printf("%lld\n", s[1]);for(int i = 1; i <= n; i++){if(st[i][1]) printf("%lld ", to[i].size());else printf("1 ");}}else{printf("%lld\n", min(s[0], s[1]));if(s[0] < s[1]){for(int i = 1; i <= n; i++){if(st[i][0]) printf("%lld ", to[i].size());else printf("1 ");}}else{for(int i = 1; i <= n; i++){if(st[i][1]) printf("%lld ", to[i].size());else printf("1 "); }} }puts("");return 0; }?
總結(jié)
以上是生活随笔為你收集整理的[树形dp]Weight the Tree Codeforces1646D的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 非常全的API接口查询
- 下一篇: 各种计算机语言的区别