题意:给出一个树,每个点有一个value,value的意义是去掉这个点之后所有连通分量中点最多的那个连通分量的点数,这棵树的重心为所有点value的最小值,求重心,及重心都有谁。
解法:貌似是个树形dp,不过不太懂树形dp···学了一下也没太明白这题为啥是树形dp···觉得其实是深搜···嗯···
随便找一个点当做根,我选了点1,每个点的value = max{max{sum[j]}, n - sum - 1},sum为所有儿子为根时的节点个数,直接搜就好。
对了···多组输入会PE···坑爹的OJ···
代码:
#include<stdio.h> #include<iostream> #include<algorithm> #include<string> #include<string.h> #include<math.h> #include<limits.h> #include<time.h> #include<stdlib.h> #include<map> #include<queue> #include<set> #include<stack> #include<vector> #define LL long long using namespace std; vector <int> al[16005];//邻接表存边 int n; int dp[16005]; int dfs(int v, int u) { int len = al[v].size(); int res = 0, sum = 0; for(int i = 0; i < len; i++) { if(al[v][i] != u)//判断是不是父亲节点 { int tmp = dfs(al[v][i], v); res = max(res, tmp); sum += tmp; } } dp[v] = max(res, n - sum - 1); return sum + 1; } int main() { scanf("%d", &n); memset(dp, -1, sizeof(dp)); for(int i = 0; i < n - 1; i++) { int v, u; scanf("%d%d", &v, &u); al[v].push_back(u); al[u].push_back(v); } dfs(1, 0); int ans = 16005; for(int i = 1; i <= n; i++) ans = min(ans, dp[i]); int prt[16005] = {0}; int cnt = 0; for(int i = 1; i <= n; i++) if(dp[i] == ans) prt[cnt++] = i; printf("%d %d ", ans, cnt); for(int i = 0; i < cnt; i++) { if(i) printf(" "); printf("%d", prt[i]); } printf(" "); return 0; }