来源:JZOJ #454
题目描述
政府邀请了你在火车站开饭店,但不允许同时在两个相连接的火车站开。
任意两个火车站有且只有一条路径,每个火车站最多有 50 50 50 个和它相连接的火车站。
告诉你每个火车站的利润,问你可以获得的最大利润为多少。
例如下图是火车站网络:
最佳投资方案是在
1
,
2
,
5
,
6
1,2,5,6
1,2,5,6 这
4
4
4 个火车站开饭店可以获得利润为
90
90
90
解题思路
- 我们用 g [ i ] g[i] g[i] 表示在第 i i i 个点开饭店可获得的最大利润;
- f [ i ] f[i] f[i] 表示第 i i i 个点不开饭店可获得的最大利润;
- 可得状态转移方程:
- f [ x ] + = g [ y ] f[x]+= g[y] f[x]+=g[y]( y y y 为 x x x 的子节点)
- g [ x ] + = m a x ( f [ y ] , g [ y ] ) g[x]+=max(f[y],g[y]) g[x]+=max(f[y],g[y])( y y y 为 x x x 的子节点)
- 用邻接表存储, d f s dfs dfs, A C ! AC! AC!
代码君
#include <bits/stdc++.h>
using namespace std;
int vis[200010],f[200010],v[200010],g[200010],linkk[200010];
int n,t=0;
struct node
{
int y,next;
}e[200010];
void insert(int x,int y) //邻接表存储
{
e[++t].y=y;
e[t].next=linkk[x]; linkk[x]=t;
}
void dfs(int x)
{
f[x]=v[x];
for (int i=linkk[x];i;i=e[i].next)
{
int y=e[i].y;
if (!vis[y])
{
vis[y]=1; //标记
dfs(y);
f[x]+=g[y]; //状态转移
g[x]+=max(f[y],g[y]);
}
}
}
int main()
{
freopen("profit.in","r",stdin);
freopen("profit.out","w",stdout);
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%d",&v[i]);
for (int i=1;i<n;i++)
{
int x,y;
scanf("%d %d",&x,&y);
insert(x,y); //邻接表插入
insert(y,x);
}
memset(f,0,sizeof(g));
memset(g,0,sizeof(f));
memset(vis,0,sizeof(vis));
vis[1]=1;
dfs(1);
printf("%d",max(f[1],g[1]));
return 0;
}