树的重心(树形dp)

在这里插入图片描述
树的重心性质:
在这里插入图片描述

题解:
在这里插入图片描述

代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
#include<stack>
#include<map>
#include<cmath>
#include<cstdlib>
#include<string>
#include<vector>
#include<set>
using namespace std;
#define scd(n) scanf("%d",&n)
#define scdd(a,b) scanf("%d%d",&a,&b)
#define scddd(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define rep(i,n) for(int (i)=0;(i)<(n);i++)
#define rep1(i,n) for(int (i)=1;(i)<=(n);i++)
#define pb push_back
#define lowbit(x) x&(-x)
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int>PII;
const int N = 1e5+10;
const int INF = 0x3f3f3f3f;
const LL inf = 0x3f3f3f3f3f3f3f3f;
LL mod = 998244353;
vector<int>tree[N];
int dp[N];  //dp[u]表示以u为根节点的子树中节点的数量
int res;
int n;
int weight;

void dfs(int u,int fa)
{
    int sum=0; 
    dp[u]=1;
    for(auto son:tree[u]){
        if(son==fa) continue;
        dfs(son,u);
        dp[u]+=dp[son];
        sum=max(sum,dp[son]);
    }
    sum=max(sum,n-dp[u]);
   if(res>sum){
        weight=u;  //更新重心
        res=sum;  //更新节点的最大值
   }
}

void solve()
{
    scd(n);
    res=INF;
    rep(i,n-1){
        int x,y;
        scdd(x,y);
        tree[x].pb(y);
        tree[y].pb(x);
    }
    dfs(1,0);
    cout << weight << ' ' << res << endl;
}

int main()
{
   solve();
    return 0;
}

下面是一道模板题
题目链接

机翻:
去年,芝加哥到处都是黑帮斗殴和奇怪的谋杀。警察局长真的厌倦了这些犯罪行为,决定逮捕黑手党头目。

不幸的是,芝加哥黑手党的结构相当复杂。有n个已知的与黑手党有关的人。警方追踪他们的活动已经有一段时间了,知道他们中的一些人在互相通信。根据收集到的数据,警察局长建议黑手党的等级可以被描绘成一棵树。黑手党的头目教父(教父)是树的根,如果某人用树中的一个节点来表示,那么它的直接下属就用该节点的子节点来表示。为了达到阴谋的目的,匪徒们只与他们的直接下属和直接主人沟通。

不幸的是,虽然警察知道黑帮的通讯,但他们不知道谁是通讯高手。因此,他们只有一个无方向的通信树,不知道谁是教父。

基于这一想法,黑手党教父最可能想要控制,警察局长提出了一个建议,教父是这样一个人,在删除它后通信树的大小最大剩余的连接组件是尽可能小。帮助警察找到所有可能的教父,他们会逮捕他们。

题意:就是让你找出树的所有重心

题解:树形dp,不过需要注意的是,开vector会TLE,需要写链式前向星

代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
#include<stack>
#include<map>
#include<cmath>
#include<cstdlib>
#include<string>
#include<vector>
#include<set>
using namespace std;
#define scd(n) scanf("%d",&n)
#define scdd(a,b) scanf("%d%d",&a,&b)
#define scddd(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define rep(i,n) for(int (i)=0;(i)<(n);i++)
#define rep1(i,n) for(int (i)=1;(i)<=(n);i++)
#define pb push_back
#define lowbit(x) x&(-x)
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int>PII;
const int N = 5e4+10;
const int INF = 0x3f3f3f3f;
const LL inf = 0x3f3f3f3f3f3f3f3f;
LL mod = 998244353;
int h[N],e[N<<1],ne[N<<1],idx;
int dp[N];  //dp[u]表示以u为根节点的子树中节点的数量
int res;
int n;
int cnt;
int weight[N];

void add(int a,int b)
{
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}

void dfs(int u,int fa)
{
    dp[u]=1;
    int sum=0;
    for(int i=h[u];i!=-1;i=ne[i]){
        int son=e[i];
        if(son==fa) continue;
        dfs(son,u);
        dp[u]+=dp[son];
        sum=max(sum,dp[son]);
    }
    sum=max(sum,n-dp[u]);
    if(sum<res){
        cnt=0;  //这一步很关键,起到更新最小值的作用
        weight[cnt++]=u;
        res=sum;
    }else if(sum==res){
        weight[cnt++]=u;
    }
    /*
    另一种写法:
    if(sum<=n/2) weight[cnt++]=u;
    */
}

void solve()
{
    memset(h,-1,sizeof h);
    scd(n);
    rep(i,n-1){
        int x,y;
        scdd(x,y);
        add(x,y);
        add(y,x);
    }
    res=INF;
    dfs(1,0);
    sort(weight,weight+cnt);
    for(int i=0;i<cnt;i++) cout << weight[i] << ' ';
}

int main()
{
   solve();
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值