题意:给一棵n个节点的无根树,问去掉那一点可以使各连通分支中的节点数均<=n/2。
分析:任意选定一个根,用自底向上的方法记录每棵子树的节点数。这样对于每个节点就可以通过它子树的节点数量迅速地判断它是否符合条件,别忘了还要判断它上面那个它祖宗所在的连通分支(节点数为n减去其各个子树的连通分支数再减1)。
View Code
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> using namespace std; #define maxn 10005 struct Edge { int v, next; } edge[maxn * 2]; struct Point { int id, degree; } point[maxn]; ; int n, ncount; int layer[maxn]; int head[maxn]; bool vis[maxn]; int q[maxn]; int num[maxn]; bool ans[maxn]; bool operator <(const Point &a, const Point &b) { return a.degree > b.degree; } void addedge(int a, int b) { edge[ncount].v = b; edge[ncount].next = head[a]; head[a] = ncount++; } void input() { scanf("%d", &n); memset(head, -1, sizeof(head)); for (int i = 0; i < n - 1; i++) { int a, b; scanf("%d%d", &a, &b); a--; b--; addedge(a, b); addedge(b, a); } } void bfs() { int front = 0, rear = 0; memset(vis, 0, sizeof(vis)); q[rear++] = 0; vis[0] = true; layer[0] = 0; while (front != rear) { int u = q[front++]; for (int i = head[u]; ~i; i = edge[i].next) { int v = edge[i].v; if (vis[v]) continue; q[rear++] = v; layer[v] = layer[u] + 1; vis[v] = true; } } } void make() { for (int i = 0; i < n; i++) { point[i].id = i; point[i].degree = layer[i]; } } void work() { memset(ans, 0, sizeof(ans)); for (int i = 0; i < n; i++) { int u = point[i].id; bool ok = true; num[u] = 1; for (int j = head[u]; ~j; j = edge[j].next) { int v = edge[j].v; if (layer[v] >= layer[u]) { num[u] += num[v]; if (num[v] > n / 2) ok = false; } } if (n - num[u] > n / 2) ok = false; ans[u] = ok; } for (int i = 0; i < n; i++) if (ans[i]) printf("%d\n", i + 1); } int main() { //freopen("t.txt", "r", stdin); input(); bfs(); make(); sort(point, point + n); work(); return 0; }