杭电多校 City Upgrading 树形DP

题目地址

杭电多校 City Upgrading 树形DP_第1张图片
输入

2
7
13 20 1 20 6 9 8
1 2
1 3
2 4
2 5
3 6
5 7
4
1 17 13 4
1 2
1 3
3 4

输出

27
5

思路看此

AC code

#include 
#include 
#include 
#include 
using namespace std;
#define int long long
const int N = 2e5 + 10;
int e[N<<1],ne[N<<1],h[N],idx;
int f[N][3];
int a[N];
bool has[N];
void add(int a,int b)
{
	e[idx] = b,ne[idx] = h[a],h[a] = idx++;
}

void dfs(int u,int fa)
{
	f[u][0] = a[u];
	int sum = 0;
	int mincost = 1e10;
	for(int i = h[u];~i;i = ne[i])
	{
		int v = e[i];
		if(v == fa) continue;
		dfs(v,u);
		int t = min(f[v][0],f[v][2]);//无父结点覆盖的最小花费方案
//		选取当前结点
		f[u][0] += min(t,f[v][1]);
		
//		父结点覆盖 u 的情况
		f[u][1] += t;
		
//		子节点覆盖 u 的情况
		f[u][2] += t;
		if(f[v][0] < f[v][2])
			sum++;
		else
			mincost = min(mincost,f[v][0]-f[v][2]);
	}
	if(!sum)
		f[u][2] += mincost;
}

void solve()
{
	int n;
	cin >> n;
//	初始化
	memset(h,-1,sizeof h);
	memset(has,0,sizeof has);
	memset(f,0,sizeof(f));
	idx = 0;

	for(int i = 1;i <= n;i ++ ) cin >> a[i];

	for(int i = 1;i <= n - 1;i ++ )
	{
		int u,v;
		cin >> u >> v;
		add(u,v);
		add(v,u);
		has[v] = true;
	}
	int root = -1;
	for(int i = 1;i <= n;i ++ )
		if(!has[i]) root = i;
	dfs(root,-1);
	cout << min(f[root][0],f[root][2]) << "\n";
}

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	int T;
	cin >> T;
	while(T -- ) solve();
}

你可能感兴趣的:(算法题解,算法)