多校第三场 1010 hdu 5325 Crazy Bobo(拓扑排序+树形dp)

本文探讨了一种在树形结构中寻找最大有序点集的方法,通过拓扑排序和动态规划实现最优解。算法核心在于确保点集内点权按降序排列,并且每两点间路径上点权不超前点权。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:

点击打开链接

题目大意:

给一棵树,每个点都有点权,定义一个集合,集合里的点是连通的,且按照点权降序排序之后,第i个点到达第i+1个点的路径上的点点权均小于点i,问这样的点集的规模最大是多少?

题目分析:

因为在树上,任意两点之间只有一条路径,那么我们假设找到了这个最大的集合,那么它会满足哪些性质呢?

1.对于第i个点,第i+1个点,第i+2个点,i+1和i+2的链上一定不会有i,因为路径不能有点权大于i的点权的点,所以我们得到的这个点集上的点一定时点权排序后点在链上相邻

2.那么我如果保留原图中本来相邻的点,出点大于入点的那条边,然后因为本身是树,所以我们得到一个有向无环图,那么我们可以按照拓扑序进行动态规划,统计出按照拓扑序能够到达I点的点的子树,然后枚举每个点作为集合中最小点的情况,通过比较得到最大的集合的规模

代码如下:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <queue>
#define MAX 500007

using namespace std;

int n;
int w[MAX];
int in[MAX];
int cnt[MAX];
vector<int> e[MAX];

void init ()
{
    for ( int i = 0 ; i < MAX ; i++ )
        e[i].clear();
    memset ( in , 0 , sizeof ( in ));
    memset ( cnt , 0 , sizeof ( cnt ));
}

void add ( int u , int v )
{
    e[u].push_back ( v );
}

void topSort ( )
{
    queue<int> q;
    for ( int i = 1 ; i <= n ; i++ )
    {
        if ( !in[i] )
        {
            q.push ( i );
        }
        cnt[i] = 1;
    }
    while ( !q.empty() )
    {
        int u = q.front();
        q.pop();
        for ( int i = 0 ; i < e[u].size() ; i++ )
        {
            int v = e[u][i];
            in[v]--;
            cnt[v] += cnt[u];
            if ( !in[v] ) q.push ( v );
        }
    }
}

int main ( )
{
    int u,v;
    while ( ~scanf ( "%d" , &n ))
    {
        init ();
        for ( int i = 1 ; i <= n ; i++ )
            scanf ( "%d" , &w[i] );
        for ( int i = 0 ; i < n-1 ; i++ )
        {
            scanf ( "%d%d" , &u , &v );
            if ( w[u] < w[v] )
                swap ( u , v );
            add ( u , v );
            in[v]++;
        }
        topSort();
        int ans = 0;
        for ( int i = 1 ; i <= n ; i++ )
            ans = max ( ans , cnt[i] );
        printf ( "%d\n" , ans );
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值