CodeForces 1244D. Paint the Tree

题意:树是一个无向联通的无环图,现在给你一棵树,你有三种不同的颜色1,2,3可以选择,你要把树上的每个点涂一种颜色,使得任何一条由三个不同的点构成的路(这一段路上只能有三个点,就是0-0-0),他们之间的颜色是不同的。现在给你三种颜色,每种颜色染每个点需要的花费。请你给出一种染色的方案,满足以上条件使总花费最小。

分析:我们可以发现,不合法的情况是一个点连了大于等于3个点,即存在一个点的度数是大于等于3的。然后我们可以发现整个树是一条链,意味着当我们确定两个相邻的点的颜色后,其它点的颜色可以根据这两个点的颜色全部推出,比如p1点为a颜色,p2点为b颜色,那么第三个点的颜色为6 - a - b,我们只要遍历一下树,就可以推出所有颜色值。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>

using namespace std;
using LL = long long;
const int N = 100005;
int h[N], e[2 * N], ne[2 * N], idx;
int c[4][N];
int g[N], f[N];
int d[N];

void add(int a, int b)
{
	e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}

LL dfs(int u, int fa, int color)
{
	g[u] = color;

	LL cost = c[color][u];
	for (int i = h[u]; i != -1; i = ne[i])
	{
		int j = e[i];
		if (j == fa) continue;
		cost += dfs(j, u, 6 - g[u] - g[fa]);
	}
	return cost;
}
LL cal(int a, int b)
{
	LL cost = 0;
	g[1] = a;
	cost += c[a][1];
	int p2;
	for (int i = h[1]; i != -1; i = ne[i])
	{
		int j = e[i];
		p2 = j;
		cost += c[b][p2];
		break;
	}
	g[p2] = b;

	int p1 = 1;

	for (int i = h[p1]; i != -1; i = ne[i])
	{
		int j = e[i];
		if (j == p2) continue;
		cost += dfs(j, p1, 6 - a - b);
	}

	for (int i = h[p2]; i != -1; i = ne[i])
	{
		int j = e[i];
		if (j == p1) continue;
		cost += dfs(j, p2, 6 - a - b);
	}
	return cost;
}

int main()
{
	int n;
	scanf("%d", &n);

	for(int i = 1; i <= 3; ++i)
		for (int j = 1; j <= n; ++j)
		{
			scanf("%d", &c[i][j]);
		}

	memset(h, -1, sizeof h);

	int u, v;
	for (int i = 1; i < n; ++i)
	{
		scanf("%d%d", &u, &v);
		++d[u], ++d[v];
		add(u, v), add(v, u);
	}

	bool flag = true;
	for (int i = 1; i <= n; ++i)
	{
		if (d[i] >= 3)
		{
			flag = false;
			break;
		}
	}

	if (!flag)
	{
		cout << -1 << endl;
	}
	else
	{
		LL mx = 1e18;
		for (int i = 1; i <= 3; ++i)
		{
			for (int j = 1; j <= 3; ++j)
			{
				if (j != i)
				{
					LL cost = cal(i, j);
					if (mx > cost)
					{
						mx = cost;
						for (int k = 1; k <= n; ++k)
							f[k] = g[k];
					}
				}
			}
		}
		cout << mx << endl;
		for (int i = 1; i <= n; ++i)
			cout << f[i] << " ";
	}

	

	return 0;
}
原文地址:https://www.cnblogs.com/pixel-Teee/p/13232433.html