JZOJ #454 最大利润(树形dp入门)

来源:JZOJ #454

题目描述

政府邀请了你在火车站开饭店,但不允许同时在两个相连接的火车站开。

任意两个火车站有且只有一条路径,每个火车站最多有 50 50 个和它相连接的火车站。

告诉你每个火车站的利润,问你可以获得的最大利润为多少。

例如下图是火车站网络:
在这里插入图片描述
最佳投资方案是在 1 2 5 6 1,2,5,6 4 4 个火车站开饭店可以获得利润为 90 90

解题思路

  • 我们用 g [ i ] g[i] 表示在第 i i 个点开饭店可获得的最大利润;
  • f [ i ] f[i] 表示第 i i 个点不开饭店可获得的最大利润;
  • 可得状态转移方程:
  • f [ x ] + = g [ y ] f[x]+= g[y] y y x x 的子节点)
  • g [ x ] + = m a x ( f [ y ] , g [ y ] ) g[x]+=max(f[y],g[y]) y y x x 的子节点)
  • 用邻接表存储, d f s dfs A C ! 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;
}
发布了27 篇原创文章 · 获赞 33 · 访问量 1673

猜你喜欢

转载自blog.csdn.net/qq_43081996/article/details/104210303
今日推荐