题目Link
题目学习link1
题目学习link2
题目学习link3
%%% 受益匪浅!
--------------------------------
通过了解题意可知
当 n = 2 时 为一种特殊情况,特判一下(样例温和捏~
当 n > 2 时 当一个节点为good节点时,与其相连的节点一定为非good点
这样模型就显现出来了 类似于link2中所讲树的最小点覆盖问题
这里用 0 表示 该点不是good点 , 1 表示为good点
且只有 0-0 , 0- 1 两种情况,dp即可求出最大的 good 点个数
由于还要求最小的节点权值和,开个结构体用dp数组一起求
状态转移见代码
/*
*@author:bzdhxs
*@date:2022/03/15
*@URL:
*/
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<string>
#include<vector>
#include<map>
#include<queue>
using namespace std;
template <typename T>
inline void read(T &s){s = 0;T w = 1, ch = getchar();while (!isdigit(ch)) { if (ch == '-') w = -1; ch = getchar(); }while (isdigit(ch)) { s = (s << 1) + (s << 3) + (ch ^48); ch = getchar();} s *= w;}
template <typename T>
inline void write(T s){if (s < 0) putchar('-'), s = -s;if (s > 9) write(s / 10);putchar(s % 10 + '0');}
#define int long long
#define _orz ios::sync_with_stdio(false),cin.tie(0)
#define mem(str,num) memset(str,num,sizeof(str))
#define forr(i,a,b) for(int i = a; i <= b;i++)
#define forn(i,n) for(int i = 0; i < n; i++)
#define dbg() cout <<"0k!"<< endl;
typedef long long ll;
int pri[16] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53};
const int inf = 0x3f3f3f3f;
const int INF = ~0ULL;
const int N = 1e6+10;
int n;
vector<int> g[200005];
struct node{
int g,s; // g 记录好点个数 s 记录权值和
//用来取较优的点
bool operator>(const node&t)const{
if(g != t.g) return g > t.g; //优先good点个数,相同取权值小的
return s < t.s;
}
}dp[200005][2];
//树形dp
void dfs1(int u,int fa){
dp[u][0].s = 1;// 非good点权值为1,最小
dp[u][1].s = g[u].size();// 作为good点权值为直接连边的个数
dp[u][1].g = 1;// 为good点故为1
for(auto v:g[u]){
if(v == fa) continue;
dfs1(v,u);
// u作为good点
dp[u][1].g += dp[v][0].g; // 直接连边的均为非good点取dp[v][0]
dp[u][1].s += dp[v][0].s;
// 当 u为非good点的时候,v可以为good 也可以为非good 取最优;
int best = (dp[v][0] > dp[v][1])?0:1;
dp[u][0].g += dp[v][best].g;
dp[u][0].s += dp[v][best].s;
}
}
int w[200005];
// 再次遍历更新点的权值
void dfs2(int u,int fa,int bes){
// good 就取相连点个数 否则取1;
w[u] = (bes)?g[u].size():1;
for(auto v:g[u]){
if(v == fa) continue;
// 当前节点为good那么相邻节点就为非good
if(bes) dfs2(v,u,0);
else{
int best = (dp[v][0] > dp[v][1])?0:1;
dfs2(v,u,best);
}
}
}
signed main()
{
cin >> n;
forr(i,1,n-1){
int l,r;cin >> l >> r;
g[l].push_back(r);
g[r].push_back(l);
}
//特判2
if(n == 2){
cout << 2 <<" " << 2 << endl;
cout << 1 <<" "<< 1 << endl;
return 0;
}
dfs1(1,0);
int best = (dp[1][0] > dp[1][1])?0:1;
//求每个点的权值
dfs2(1,0,best);
// 输出1节点最优情况
cout << dp[1][best].g <<" "<<dp[1][best].s<<endl;
forr(i,1,n) cout << w[i] <<" \n"[i==n];
return 0;
}