例题1:
hdu1520:http://acm.hdu.edu.cn/showproblem.php?pid=1520
题意:
给一颗树,给各个结点的权值,选择若干结点,结点之间不能直接相连,求结点的最大权值和(即任意结点之间没有父子关系)
解析:
树的最大独立集合,在树上dp操作,选了该结点,就一定不能选该结点的子节点
dp[i][0]表示以i为根的树,不选该根结点的权值最大和
dp[i][1]表示以i为根的树,选该根结点的权值最大和
dp[x][0]+=max(dp[v][1],dp[v][0]);
dp[x][1]+=dp[v][0];
先处理子节点,再处理父节点
AC:
用树形dp解决
#include<bits/stdc++.h>
#define MAXN 20005
using namespace std;
int dp[MAXN][2];
int f[MAXN];
vector<int> vc[MAXN];
void dfs(int x)
{
int len=vc[x].size();
for(int i=0;i<len;i++)
{
int v=vc[x][i];//子节点
dfs(v);//要先出来子节点
dp[x][0]+=max(dp[v][1],dp[v][0]);
dp[x][1]+=dp[v][0];
}
}
int main()
{
int n,x,a,b;
while(scanf("%d",&n)!=EOF)
{
for(int i=0;i<MAXN;i++)
f[i]=-1;
for(int i=1;i<=n;i++)
{
vc[i].clear();
scanf("%d",&x);
dp[i][1]=x;
dp[i][0]=0;
}
while(1)
{
scanf("%d%d",&a,&b);
if(a==0&&b==0)
break;
f[a]=b;
vc[b].push_back(a);
}
int ans=0;
for(int i=1;i<=n;i++)
{
if(f[i]==-1)
{
dfs(i);
ans=max(ans,max(dp[i][0],dp[i][1]));
}
}
printf("%d\n",ans);
}
return 0;
}
例题2:
链接:https://ac.nowcoder.com/acm/problem/15748
解析:
树形dp,树的最大独立集
告诉了出发点,出发点必选ans=dp[s][1]
ac:
#include<bits/stdc++.h>
#define MAXN 500005
using namespace std;
vector<int> vc[MAXN];
int dp[MAXN][2]={0};
void dfs(int x,int pre)
{
int len=vc[x].size();
for(int i=0;i<len;i++)
{
int v=vc[x][i];
if(v==pre)
continue;
dfs(v,x);
dp[x][1]+=dp[v][0];
dp[x][0]+=max(dp[v][1],dp[v][0]);
}
}
int main()
{
int n,s,a,b;
scanf("%d%d",&n,&s);
for(int i=1;i<=n;i++)
{
dp[i][1]=1;
dp[i][0]=0;
}
for(int i=1;i<n;i++)
{
scanf("%d%d",&a,&b);
vc[a].push_back(b);
vc[b].push_back(a);
}
dfs(s,-1);
//printf("%d\n",max(dp[s][1],dp[s][0]));wa,出发地已经选择了,s必去
printf("%d\n",dp[s][1]);//注意出发地一定选择
return 0;
}
http://acm.hdu.edu.cn/showproblem.php?pid=6725
题意:
给你一棵n个点的树,对于节点i,你要给它标上一个[li,ri]之间的数,要求所有边两端节点上标的数字的差的绝对值的总和最大
解析:
每次肯定是选择L或者R.
类似求树形dp最大独立集
#include<bits/stdc++.h>
#define MAXN 1000005
#define ll long long
using namespace std;
ll to[MAXN],nxt[MAXN],head[MAXN];
ll tot=0;
ll in[MAXN];
ll l[MAXN],r[MAXN];
void add(ll u,ll v)
{
to[++tot]=v;
nxt[tot]=head[u];
head[u]=tot;
}
ll LL[MAXN],RR[MAXN];
ll dfs(ll x,ll fa)
{
for(ll i=head[x];i;i=nxt[i])
{
ll v=to[i];
if(v==fa)
continue;
dfs(v,x);
LL[x]+=max(abs(l[x]-l[v])+LL[v],abs(l[x]-r[v])+RR[v]);
RR[x]+=max(abs(r[x]-l[v])+LL[v],abs(r[x]-r[v])+RR[v]);
}
}
void init()
{
tot=0;
for(int i=0;i<MAXN;i++)
head[i]=in[i]=LL[i]=RR[i]=0;
}
int main()
{
ll t,n,u,v;
scanf("%lld",&t);
while(t--)
{
init();
scanf("%lld",&n);
for(ll i=1;i<=n-1;i++)
{
scanf("%lld%lld",&u,&v);
add(u,v);
add(v,u);
in[u]++;
in[v]++;
}
for(ll i=1;i<=n;i++)
scanf("%lld%lld",&l[i],&r[i]);
ll ans=0;
for(ll i=1;i<=n;i++)
{
if(in[i]==1)
{
dfs(i,0);
ans=max(LL[i],RR[i]);//结果为从根结点开始选L或R作为起始点
break;
}
}
printf("%lld\n",ans);
}
return 0;
}