标签:
题目大意:给出一个无向图(树),要求你删除掉其中一个点,使剩下的点构成的子树中,节点数最大的那个值达到最小
解题思路:因为给出的是一个无根树,第一个想法就是先把它转成有根树,将1当成根
设sum[i]为以i为根节点的子树有多少个节点,那么sum[1] - sum[i]就相当于是排除了i的所有子节点的另一棵子树的节点总数了
设dp[i]为去掉了i节点后的剩余节点所构成的子树的节点的最大值
那么dp[i] = max(dp[i], sum[son]) son指的是和i相连的子节点
还有另一棵子树,就是sum[1] - sum[i],还得再比较一次
感觉SGU的输入和输出挺特别的,要注意
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
#define maxn 16010
#define INF 0x3f3f3f3f
vector<int> tree[maxn];
int dp[maxn], vis[maxn], Sum[maxn], ans[maxn];
int N, cnt, Min;
void dfs(int cur) {
Sum[cur] = 1;
vis[cur] = 1;
for(int i = 0; i < tree[cur].size(); i++)
if(!vis[tree[cur][i]]) {
dfs(tree[cur][i]);
Sum[cur] += Sum[tree[cur][i]];
}
}
void dfs2(int cur, int f) {
dp[cur] = 0;
vis[cur] = 1;
for(int i = 0; i < tree[cur].size(); i++) {
if(!vis[tree[cur][i]]) {
dfs2(tree[cur][i], f);
dp[cur] = max(dp[cur], Sum[tree[cur][i]]);
}
}
dp[cur] = max(dp[cur], Sum[f] - Sum[cur]);
if(dp[cur] == Min) {
ans[cnt] = cur;
cnt++;
return ;
}
else if(dp[cur] < Min) {
Min = dp[cur];
cnt = 0;
ans[cnt] = cur;
cnt++;
return ;
}
}
void solve() {
dfs(1);
for(int i = 1; i <= N; i++)
vis[i] = 0;
Min = INF;
cnt = 0;
dfs2(1,1);
printf("%d %d\n", Min, cnt);
sort(ans, ans + cnt);
printf("%d", ans[0]);
for(int i = 1; i < cnt; i++)
printf(" %d", ans[i]);
}
void init() {
for(int i = 1; i <= N; i++) {
tree[i].clear();
vis[i] = 0;
}
int x, y;
for(int i = 0; i < N - 1; i++) {
scanf("%d%d", &x, &y);
tree[x].push_back(y);
tree[y].push_back(x);
}
}
int main (){
scanf("%d", &N);
init();
solve();
return 0;
}
SGU - 134 Centroid 无根树转有根树 + 树形DP
标签:
原文地址:http://blog.csdn.net/l123012013048/article/details/45704097