Paint the Tree(链dfs)

题目描述

You are given a tree consisting of nn vertices. A tree is an undirected connected acyclic graph.

Example of a tree.You have to paint each vertex into one of three colors. For each vertex, you know the cost of painting it in every color.

You have to paint the vertices so that any path consisting of exactly three distinct vertices does not contain any vertices with equal colors. In other words, let's consider all triples (x, y, z)(x,y,z) such that x \neq y, y \neq z, x \neq zx​=y,y​=z,x​=z , xx is connected by an edge with yy , and yy is connected by an edge with zz . The colours of xx , yy and zz should be pairwise distinct. Let's call a painting which meets this condition good.

You have to calculate the minimum cost of a good painting and find one of the optimal paintings. If there is no good painting, report about it.

输入格式

The first line contains one integer nn (3 \le n \le 100\,000)(3≤n≤100000) — the number of vertices.

The second line contains a sequence of integers c_{1, 1}, c_{1, 2}, \dots, c_{1, n}c1,1​,c1,2​,…,c1,n​ (1 \le c_{1, i} \le 10^{9})(1≤c1,i​≤109) , where c_{1, i}c1,i​ is the cost of painting the ii -th vertex into the first color.

The third line contains a sequence of integers c_{2, 1}, c_{2, 2}, \dots, c_{2, n}c2,1​,c2,2​,…,c2,n​ (1 \le c_{2, i} \le 10^{9})(1≤c2,i​≤109) , where c_{2, i}c2,i​ is the cost of painting the ii -th vertex into the second color.

The fourth line contains a sequence of integers c_{3, 1}, c_{3, 2}, \dots, c_{3, n}c3,1​,c3,2​,…,c3,n​ (1 \le c_{3, i} \le 10^{9})(1≤c3,i​≤109) , where c_{3, i}c3,i​ is the cost of painting the ii -th vertex into the third color.

Then (n - 1)(n−1) lines follow, each containing two integers u_juj​ and v_jvj​ (1 \le u_j, v_j \le n, u_j \neq v_j)(1≤uj​,vj​≤n,uj​​=vj​) — the numbers of vertices connected by the jj -th undirected edge. It is guaranteed that these edges denote a tree.

输出格式

If there is no good painting, print -1−1 .

Otherwise, print the minimum cost of a good painting in the first line. In the second line print nn integers b_1, b_2, \dots, b_nb1​,b2​,…,bn​ (1 \le b_i \le 3)(1≤bi​≤3) , where the ii -th integer should denote the color of the ii -th vertex. If there are multiple good paintings with minimum cost, print any of them.

题意翻译

有一棵树,有3种颜色,第ii个节点染成第jj种颜色的代价是c_{j,i}cj,i​,现在要你求出一种染色方案,使得总代价最小,且对于任意三个相邻的节点,颜色不能相同。输出最小代价与其中一种方案。无解输出-1−1。

3\le n\le 10^53≤n≤105

输入输出样例

输入 #1复制

3
3 2 3
4 3 2
3 1 3
1 2
2 3

输出 #1复制

6
1 3 2 

输入 #2复制

5
3 4 2 1 2
4 2 1 5 4
5 3 2 1 1
1 2
3 2
4 3
5 3

输出 #2复制

-1

输入 #3复制

5
3 4 2 1 2
4 2 1 5 4
5 3 2 1 1
1 2
3 2
4 3
5 4

输出 #3复制

9
1 3 2 1 3 

说明/提示

All vertices should be painted in different colors in the first example. The optimal way to do it is to paint the first vertex into color 11 , the second vertex — into color 33 , and the third vertex — into color 22 . The cost of this painting is 3 + 2 + 1 = 63+2+1=6 .

 


 

画画发现其实一个点度数>=3的时候必定是不成立的。所以整个树就退化成了一条链子。

所以情况有:

从头到尾重新标记为1,2,3,...,n。染色情况只有六种(数字代表颜色):

  • 1,2,3,1,2,3,1,2,3,...
  • 1,3,2,1,3,2,1,3,2,...
  • 2,1,3,2,1,3,2,1,3,...
  • 2,3,1,2,3,1,2,3,1,...
  • 3,1,2,3,1,2,3,1,2,...
  • 3,2,1,3,2,1,3,2,1,...

枚举每一个状态进行dfs就可以辣。

(开始自己推出来退化了,结果还在二叉树上dp..简直不要太石乐志

代码上z注意从1,2,3染色直接用n-x-y来方便获得下一个颜色,链子dfs的时候只要判不是遍历到父亲节点就好了

#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<cstdio>
#include<algorithm>
#define debug(a) cout<<#a<<"="<<a<<endl;
using namespace std;
const int maxn=1e5+100;
typedef long long LL;
LL c[4][maxn];
LL col[maxn],s[maxn];
vector<LL>g[maxn];
LL nex(LL x,LL y)
{
	return 6-x-y;
}
void dfs(LL u,LL fa,LL uc,LL fc)
{
	
	for(LL i=0;i<g[u].size();i++)
	{
		LL v=g[u][i];
		if(v==fa) continue;//链不回到父亲节点就好 
		col[v]=nex(uc,fc);
		dfs(v,u,col[v],uc);
	}
}
int main(void)
{
  cin.tie(0);std::ios::sync_with_stdio(false);
  LL n;cin>>n;
  for(LL i=1;i<=n;i++) cin>>c[1][i];
  for(LL i=1;i<=n;i++) cin>>c[2][i];
  for(LL i=1;i<=n;i++) cin>>c[3][i];
  LL x,y;
  for(LL i=1;i<n;i++)
  {
  	 cin>>x>>y;
  	 g[x].push_back(y);g[y].push_back(x);
  }
  for(LL i=1;i<=n;i++)
  {
  	if(g[i].size()>=3)
  	{
  		cout<<"-1"<<endl;return 0;	
	}
  }
  LL sum=0x3f3f3f3f3f3f3f3f3f3f;//要开大!! 
  for(LL i=1;i<=3;i++){
  	for(LL j=1;j<=3;j++){
  		if(i==j) continue;
  		col[x]=i;col[y]=j;
		dfs(x,y,i,j);//随便找一条边枚举,这里从输入的最后一条边去枚举 
		dfs(y,x,j,i);//有可能输入的时候是末尾点就没法dfs了 
		LL ans=0;
		for(LL i=1;i<=n;i++) ans+=c[col[i]][i];
		if(ans<sum)
		{
			sum=ans;
			for(LL i=1;i<=n;i++)
			{
				s[i]=col[i];
			}
		}
	}
  }
  cout<<sum<<endl;
  for(LL i=1;i<=n;i++) cout<<s[i]<<" ";
  cout<<endl;
return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值