没有上司的舞会

没有上司的舞会

有一棵有n个点n-1条边的有根树,给出点权,要从中选出若干个点,保证其中任何两个点不再同一条边的端点上,求点权之和的最大值,\(1<=N<=6000\)。

本题树已经给出根,但是一定要有意识对于树的问题,转换成有根树,尤其是二叉树,可以大大简化问题。

本题显然为树形递推题,必然要表现节点这一状态,并且还有不能在同一边上的限制,于是设\(f[x][0/1]\)分别表示以x为根节点的子树中x选和不选的最大点权纸和,设\(x_i\)为x的第i个儿子,因此不难有

\[f[x][0]=\sum_{i=1}^{|son(x)|}\max(f[x_i][0],f[x_i][1])\]

\[f[x][1]=\sum_{i=1}^{|son(x)|}f[x_i][0]\]

边界:\(f[i][0]=\)对应点权,i为叶子节点编号,其余为0.

答案:\(max(f[r][0],f[r][1])\),r为根节点

参考代码:

dfs

#include <iostream>
#include <cstdio>
#define il inline
#define ri register
using namespace std;
struct point{
    point *next;int to;
}*head[6001],*pt;
int h[6001],dp[6001][2],in[6001];
il int max(int,int);
il void read(int&),link(int,int),dfs(int);
int main(){
    int n,root;read(n);
    for(int i(1);i<=n;++i)read(h[i]);
    for(int u(1),v(1);u&&v;)read(u),read(v),link(v,u),++in[u];
    for(int i(1);i<=n;++i)if(!in[i]){root=i;break;}
    dfs(root),printf("%d",max(dp[root][0],dp[root][1]));
    return 0;
}
il int max(int a,int b){
    return a>b?a:b;
}
il void dfs(int a){
    for(point *i(head[a]);i!=NULL;i=i->next)
        dfs(i->to),dp[a][0]+=max(dp[i->to][0],dp[i->to][1]),
            dp[a][1]+=dp[i->to][0];dp[a][1]+=h[a];
}
il void link(int u,int v){
    pt=new point,pt->to=v;
    pt->next=head[u],head[u]=pt;
}
il void read(int &x){
    x&=0;ri char c;while(c=getchar(),c==' '||c=='\n'||c=='\r');
    ri bool check(false);if(c=='-')check|=true,c=getchar();
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    if(check)x=-x;
}

bfs

#include <iostream>
#include <cstdio>
#include <queue>
#define il inline
#define ri register
using namespace std;
queue<int>T;
int h[6001],dp[6001][2],in[6001],
    n,pa[6001];
il void read(int&);
il int max(int,int),dag();
int main(){
    read(n);for(int i(1);i<=n;++i)read(h[i]);
    for(int u(1),v(1);u&&v;)
        read(u),read(v),pa[u]=v,++in[v];
    printf("%d",dag());
    return 0;
}
il int dag(){
    for(int i(1);i<=n;++i)if(!in[i])T.push(i),dp[i][1]=h[i];
    while(!T.empty()){
        int s(T.front());T.pop();
        dp[pa[s]][0]+=max(dp[s][0],dp[s][1]);
        dp[pa[s]][1]+=dp[s][0],--in[pa[s]];
        if(!in[pa[s]])dp[pa[s]][1]+=h[pa[s]],T.push(pa[s]);
    }int root;for(root=1;root<=n;++root)if(!pa[root])break;
    return max(dp[root][0],dp[root][1]);
}
il int max(int a,int b){
    return a>b?a:b;
}
il void read(int &x){
    x&=0;ri char c;while(c=getchar(),c==' '||c=='\n'||c=='\r');
    ri bool check(false);if(c=='-')check|=true,c=getchar();
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    if(check)x=-x;
}
上一篇:SpringCloud微服务(05):Zuul组件,实现路由网关控制


下一篇:Industrial I/O