树的最大权值独立集

来源:互联网 发布:海文网络计划 编辑:程序博客网 时间:2024/06/06 20:57

一棵树,每个点有一个权值,选择一个权值最大的无父子节点点集。

关键词:树的最大”权值“独立集

f[i][0]:以i为根的子树不选根节点最大权值,f[i][1]:以i为根的子树选根节点最大权值

f[u][1]+=f[v][0];

f[u][0]+=max(f[v][1],f[v][0]);

注:1.若所有点的权值都大于0,则树的最大”权值“独立集也是极大点独立集,即任选两个点,一定有且仅有一个在该集合中。若存在点的权值小于0,则不一定成立。

变题:选择一个无祖先与后代节点的最大权值点集

f[u]:以i为根的子树的最大权值

f[u]=max{ w[u],sum{f[v]},v是u的孩子 } 两个选择:当前节点/后代,两个选择互斥

#include<stdio.h>#include<iostream>#include<string.h>#include<algorithm>#include<map>#include<vector>#include<queue>#define ll long long#define sf scanf#define pf printf#define maxn 10000#define inf 0x3f3f3f#define INF 1ll<<60#define mem(a,b) memset(a,b,sizeof(a))#define lowbit(x) x&(-x)using namespace std;int n;int a[maxn],du[maxn];struct Edge{    int to,next;}edge[maxn];int head[maxn],tot;int f[maxn][2];//f[u][0]:子树不含u的最大欢乐值 f[u][1]:子树含u的最大欢乐值void add(int a,int b){    edge[tot].to=b,edge[tot].next=head[a],head[a]=tot++;}void dp(int u){    f[u][1]=a[u],f[u][0]=0;    for(int i=head[u];i!=-1;i=edge[i].next){        int v=edge[i].to;        dp(v);        f[u][1]+=f[v][0];        f[u][0]+=max(f[v][1],f[v][0]);    }}int main(){    //freopen("a.txt","r",stdin);    scanf("%d",&n);    for(int i=1;i<=n;i++) scanf("%d",&a[i]);    mem(head,-1),mem(du,0),mem(f,0),tot=0;    for(int i=1;i<n;i++){        int a,b;        scanf("%d%d",&a,&b);        add(b,a);        du[a]++;    }    for(int i=1;i<=n;i++)        if(!du[i]) {dp(i);printf("%d\n",max(f[i][0],f[i][1]));break;}}


0 0
原创粉丝点击