poj 1655 Balancing Act 图论基础 树的重心

来源:互联网 发布:excel重复数据筛选公式 编辑:程序博客网 时间:2024/06/09 16:16

题目

题目链接:http://poj.org/problem?id=1655

题目来源:图论基础入门。

简要题意:N个节点的树求出编号最小的树的重心和最大子树大小。

数据范围:1T20;1N20000

题解

首先给出树的重心的定义:删去之后剩余的连通块的节点数的最大值最小,也就是最为平均的分割点

也可以根据题目中的描述来了解什么是树的重心。

树的重心可以被用于树的分治中,防止Θ(N2)的极端复杂度。

需要分清楚树的重心和树的中心的区别,树的中心是直径的中间的节点。

实现

只需要一次dfs就可以求出结果。

维护son[x]1为根的树下,包含x及其后继节点的子树的大小。

对每个孩子的son[child]值加和再加1即能维护好值。

切分开来的规模,对于孩子来说就是孩子的son[child]

含有当前节点父亲的连通块的规模就是Nson[x],就是把x及以下的子树切掉就行了。

复杂度为Θ(N)

代码

#include <iostream>#include <cstdio>#include <cmath>#include <algorithm>#include <cstring>#include <stack>#include <queue>#include <string>#include <vector>#include <set>#include <map>#define pb push_back#define mp make_pair#define all(x) (x).begin(),(x).end()#define sz(x) ((int)(x).size())#define fi first#define se secondusing namespace std;typedef long long LL;typedef vector<int> VI;typedef pair<int,int> PII;LL powmod(LL a,LL b, LL MOD) {LL res=1;a%=MOD;for(;b;b>>=1){if(b&1)res=res*a%MOD;a=a*a%MOD;}return res;}// headstruct Edge {    int to, nxt;    Edge(int to, int nxt) : to(to), nxt(nxt){}    Edge() {}};const int N = 2E4+5;int head[N];int son[N];Edge e[N*2];int n, t, u, v, anssz, ansno;void addEdge(int from, int to, int cnt) {    e[cnt] = Edge(to, head[from]);    head[from] = cnt;}void dfs(int x, int p) {    int bal = 0;    son[x] = 1;    for (int i = head[x]; ~i; i = e[i].nxt) {        int nxt = e[i].to;        if (nxt == p) continue;        dfs(nxt, x);        bal = max(bal, son[nxt]);        son[x] += son[nxt];    }    bal = max(bal, n-son[x]);    if (bal < anssz || (bal == anssz && x < ansno)) {        anssz = bal;        ansno = x;    }}void init() {    memset(head, -1, sizeof head);    memset(son, 0, sizeof son);}int main(){    scanf("%d", &t);    while (t--) {        init();        int cnt = 0;        anssz = ansno = 1e9;        scanf("%d", &n);        for (int i = 1; i < n; i++) {            scanf("%d%d", &u, &v);            addEdge(u, v, cnt++);            addEdge(v, u, cnt++);        }        dfs(1, -1);        printf("%d %d\n", ansno, anssz);    }    return 0;}
0 0
原创粉丝点击