[NOI2002]贪吃的九头龙

贪吃的九头龙

题目大意

给出一棵 \(n\) 个点的树,现在要求你给这可树的每个点都染上颜色。你一共有 \(m\) 种颜色,要求第一种颜色必须染恰好 \(k\) 个点,且根节点必须染成第一种颜色,同时其他的每种颜色至少染色一个节点。

当有边相连的两个点为同一颜色时,代价为这条边的权值,否则代价为 \(0\)

求给这颗树染色的最小代价。

分析

读完题目后,考虑树形 \(DP\)

想一想怎么设状态?最开始会想到设出状态为 \(f[i][j]\) 表示以第 \(i\) 个点为根的子树中有 \(j\) 个节点染成了第一种颜色,但是这样没法更新,我们还需要一个告诉我们当前点颜色的维度。

于是设 \(f[i][j][0/1]\) 表示以第 \(i\) 个点为根的子树中有 \(j\) 个节点染成了第一种颜色,求点 \(i\) 是否染成了第一种颜色。

如何更新?

\[f[u][j][0]=min(f[u][j][0],min(f[to][t][0]+f[u][j-t][0]+(m==2)\times w[i]),f[to][t][1]+f[u][j-t][0])) \]

\[f[u][j][1]=min(f[u][j][1],min(f[to][t][1]+f[u][j-t][1]+w[i],f[to][t][0]+f[u][j-t][1])) \]

接下来我们对状态转移方程进行解释。

首先,如果当前节点染色不为 \(1\) ,它和它的儿子节点如果会产生花费,则只有一种情况,就是当 \(m=2\) 时,这两个节点若染色都不为 \(1\) ,则它们只能被染成其他颜色,而其他颜色只有一种,于是很显然会出现贡献。

反之,若 \(m>2\) ,就不会存在这样的情况。

其他地方的更新都比较容易理解,枚举一个 \(j\) ,表 \(u\) 中染色为 \(1\) 的节点数,枚举一个 \(t\) ,表 \(to\) 中染色为 \(1\) 的节点数,之后正常更新即如上。

CODE

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=3e2+10;
inline int read()
{
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9') { if(ch=='-') w*=-1; ch=getchar(); }
	while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
	return s*w;
}
int n,m,k;
int g[N][2],f[N][N][2];
int tot,v[2*N],w[2*N],nex[2*N],first[N];
inline void Add(int x,int y,int z)
{
	nex[++tot]=first[x];
	first[x]=tot;
	v[tot]=y,w[tot]=z;
}
inline void DFS(int u,int fa)
{
	f[u][0][0]=f[u][1][1]=0;
	for(register int i=first[u];i;i=nex[i]){
		int to=v[i];
		if(to==fa) continue;
		DFS(to,u);
		memcpy(g,f[u],sizeof(g));
		memset(f[u],63,sizeof(f[u]));
		for(register int j=0;j<=k;j++){ //枚举子树中1号染色点的数量 
			for(register int t=0;t<=j;t++){ //枚举子树to中一号染色点的数量 
				f[u][j][0]=min(f[u][j][0],min(f[to][t][0]+g[j-t][0]+(m==2)*w[i],f[to][t][1]+g[j-t][0]));
				f[u][j][1]=min(f[u][j][1],min(f[to][t][1]+g[j-t][1]+w[i],f[to][t][0]+g[j-t][1]));
			}
		}
	}
 } 
signed main()
{
	n=read(),m=read(),k=read();
	if(n-k<m) { puts("-1"); return 0; }
	for(register int i=1;i<n;i++){
		int x=read(),y=read(),z=read();
		Add(x,y,z),Add(y,x,z); 
	}
	memset(f,63,sizeof(f));
	DFS(1,1);
	printf("%lld\n",f[1][k][1]); 
	return 0;
}
posted @ 2021-08-21 10:09  ╰⋛⋋⊱๑落叶๑⊰⋌⋚╯  阅读(29)  评论(0编辑  收藏  举报