NKOI 3691 树上染色

                                                                            树上涂色
                                                               时间限制 : 1000MS   空间限制 : 65536 KB  
问题描述
  给出一棵有n个节点(编号1到n)的树,开始时每个节点都没有颜色。现在有A和B两种颜色,给第x号节点涂上A颜色需要花费Ax块钱,给x号节点涂上B颜色需要花费Bx块钱。
  如果i,j两个节点相邻,也就是i和j之间有边直接相连。若i号点已经涂成了A色,那么给j号点涂A色只需Aj/2块钱。若i号点已经涂成了B色,那么给j号点涂B色只需Bj/2块钱。也就是说,如果相邻点已经被涂了相同的颜色,当前点涂这种颜色的时候只需要一半的费用。

  现在需要将树上所有点都涂上颜色,问最少需要多少费用?


输入格式
第一行,一个整数n,表示节点总数
第二行,n个空格间隔的整数,分别表示给1到n号节点涂上A颜色所需费用
第三行,n个空格间隔的整数,分别表示给1到n号节点涂上B颜色所需费用
接下来n-1行,每行两个整数i和j,表示i和j节点间有边直接相连

输出格式
一行,一个整数,所需最小费用

样例输入 1
3
1 2 5
3 8 1
1 2
1 3

样例输出 1
3

样例输入 2
6
1 40 2 5 6 10
4 14 4 2 8 30
1 2
1 3
2 4
4 5
4 6

样例输出 2
25

提示
1<=n<=100

0<=Ax,Bx<=10000


状态:

f[i][0]:   以i为根的子树,涂上颜色的最小代价。其中i涂A颜色,与i连通的同色块(在子树内的)中,所有点都是以半价涂色的(即没有“涂色起点”)。
f[i][1]:  以i为根的子树,涂上颜色的最小代价。其中,i涂A颜色,与i连通的同色块中,存在一个节点是以全部代价涂色的(即有“涂色起点”)。
g[i][0]:  以i为根的子树,涂上颜色的最小代价。其中i涂B颜色,与i连通的同色块中,所有点都是以半价涂色的。
g[i][1]:  以i为根的子树,涂上颜色的最小代价。其中i涂B颜色,与i连通的同色块中,存在一个节点是以全部代价涂色的。

f[i][0]= Sum{ min( f[ j][0] , g[ j][1] ) }    j为i的所有儿子节点

1.为什么不讨论f[j][1]呢?

因为f[i][1]表示i涂颜色A,且子树中与之相连的同色连通块中都没有全价涂A色的点,所以只能讨论f[j][0];

2.为什么不讨论g[j][0]呢?

 因为g[j][0]表示j为根的子树中,与j同色的连通块全是半价的B颜色点。而j的父亲是涂的A颜色,与j连通的同色块中又没有全价的B色节点,那该同色连通块的颜色是从何点开始涂起的呢?其中必须有一个点事涂的全价B色,与g[j][0]矛盾,所以不用讨论g[j][0]。

f[i][0]:   以i为根的子树,涂上颜色的最小代价。其中i涂A颜色,与其连通的同色块(在子树内的)中,所有点都是以半价涂色的(即没有“涂色起点”)。
f[i][1]:  以i为根的子树,涂上颜色的最小代价。其中,i涂A颜色,与其连通的同色块中,存在一个节点是以全部代价涂色的(即有“涂色起点”)。
g[i][0],g[i][1]表示i涂B颜色,定义与f[ ][ ]类似

f[i][0]= Sum{ min( f[j][0] , g[j][1] ) }    j为i的所有儿子节点

f[i][1]= min{
           f[i][0]+ A[i]/2            //i涂全价A色
           f[i][0]+ ChaJia           //i的一个同色连通子树中存在节点涂全价A色
      }
     ChaJia=min{ f[j][1]-min(f[j][0] ,  g[j][1] )  }   j为i的所有儿子节点

说明:
f[i][1]表示i为根的字数中,i涂A色,且与i同色的连通块中,有一个点是全价A的最优方案。 我们可以对i涂全价A,也可以使与A同色连通的某棵子树中存在全价A的点。
而f[i][0]表示i为根的子树中,i涂A色,且与i同色的连通块全是半价A的最优方案。求f[i][1]只需在f[i][0]上做调整
如果我们直接将i涂成全价的A,即是f[i][0]+A[i]/2
如果我们不把i涂成全价的A,而是选一棵与i同色连通的且存在全价A的子树替换掉原来的子树,即是f[i][0]+ChaJia 这棵子树原来加入f[i][0]的状态是min(g[j][1],f[j][0]),而新替换进的状态是f[j][1],两者之差即为替换产生的差价

最后注意,由于有除法所以有精度差,因此出数据的时候一定要非常,非常注意

#include<cstdio>
#include<iostream>
using namespace std;
const int inf=1e9;
int n,a[205],b[205];
int f[205][5],g[205][5];
int NEXT[205],END[205],LAST[205],cnt;
void insert(int a,int b){  
    END[++cnt]=b;  
    NEXT[cnt]=LAST[a];  
    LAST[a]=cnt;  
}
void dp(int p,int fa){
	int cj1=inf,cj2=inf,temp,i,j;
	bool leaf=true;
	for(i=LAST[p],j=END[i];i;i=NEXT[i],j=END[i]){
		if(j==fa)continue;
		dp(j,p);
		leaf=false;
		temp=min(f[j][0],g[j][1]),f[p][0]+=temp,cj1=min(cj1,f[j][1]-temp);
		temp=min(g[j][0],f[j][1]),g[p][0]+=temp,cj2=min(cj2,g[j][1]-temp);
	}
	if(leaf){
		f[p][0]=a[p]/2,f[p][1]=a[p];
		g[p][0]=b[p]/2,g[p][1]=b[p];
	}
	else {
		f[p][0]+=a[p]/2,f[p][1]=f[p][0]+min(a[p]/2,cj1);
		g[p][0]+=b[p]/2,g[p][1]=g[p][0]+min(b[p]/2,cj2);
	}
}
int main(){
	scanf("%d",&n);
	int i,x,y,j;
	for(i=1;i<=n;i++)
	    scanf("%d",&a[i]);
	for(i=1;i<=n;i++)
	    scanf("%d",&b[i]);
	for(i=1;i<n;i++){
		scanf("%d%d",&x,&y);
		insert(x,y);
		insert(y,x);
	}
	dp(1,0);
	cout<<min(f[1][1],g[1][1]);
}

树节点染色是指给树数据结构中的每个节点分配一种颜色或标记,以此来帮助解决问题或进行一些特定操作。在Python中,可以通过以下方法来实现树节点染色。 首先,我们需要定义一个树节点的类,用来表示每个节点的属性和方法。该类可以包括节点的值、子节点列表、以及染色的属性等。例如: ```python class TreeNode: def __init__(self, value): self.value = value self.children = [] self.color = None ``` 接下来,我们可以定义一个函数,来对树节点进行染色操作。该函数可以使用递归的方式,不断遍历树的每个节点,并为其分配颜色。例如,可以使用深度优先搜索(DFS)或广度优先搜索(BFS)来遍历节点,并依次给每个节点染色。具体的染色规则可以根据问题的需求来定义。 以下是一个简单的示例,使用DFS对树节点进行染色: ```python def color_tree_dfs(node, colors): if node is None: return for child in node.children: color_tree_dfs(child, colors) # 给当前节点染色 if colors: node.color = colors.pop(0) else: node.color = "No color available" ``` 以上代码中,树节点的颜色是通过一个颜色列表进行分配的。函数每次从颜色列表中取出一个颜色,对当前节点进行染色,并将列表中的该颜色移除。如果颜色列表为空,则当前节点将被标记为"No color available"。 通过这样的方式,我们可以对树节点进行染色操作,并实现根据问题需求设置节点颜色。当然,具体染色的规则和递归的方式可能因实际问题的不同而有所调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值