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

来源:互联网 发布:南京行知实验幼儿园 编辑:程序博客网 时间:2024/04/30 04:47

题目链接:

点击打开链接

题目大意:

给一棵树,每个点都有点权,定义一个集合,集合里的点是连通的,且按照点权降序排序之后,第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 500007using 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 );    }}


0 0
原创粉丝点击