1. 程式人生 > 實用技巧 >洛谷 P3155 [CQOI2009]葉子的染色

洛谷 P3155 [CQOI2009]葉子的染色

洛谷 P3155 [CQOI2009]葉子的染色

洛谷傳送門

題目描述

給一棵 mm 個結點的無根樹,你可以選擇一個度數大於 11 的結點作為根,然後給一些結點(根、內部結點和葉子均可)著以黑色或白色。

你的著色方案應該保證根結點到每個葉子的簡單路徑上都至少包含一個有色結點(哪怕是這個葉子本身)。

對於每個葉結點 uu,定義 c_uc**u 為從根結點從 uu 的簡單路徑上最後一個有色結點的顏色。給出每個 c_uc**u 的值,設計著色方案,使得著色結點的個數儘量少。

輸入格式

第一行包含兩個整數 m,nm,n,其中 nn 是葉子的個數,mm 是結點總數。結點編號為 1,2,\ldots,m1,2,…,m

,其中編號 1,2,\ldots ,n1,2,…,n 是葉子。

以下 nn 行每行一個 00 或 11 的整數(00 表示黑色,11 表示白色),依次為 c_1,c_2,\ldots,c_nc1,c2,…,c**n

以下 m-1m−1 行每行兩個整數 a,ba,b,表示結點 aa 和 bb 有邊相連。

輸出格式

僅一個數,即著色結點數的最小值。


題解:

2020.11.14模擬賽T3滿分場

樹形DP。

展示了一下樹形DP的寶貴心路歷程。

程式碼:

#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=1e6+6;
int n,m;
int opt[maxn],cnt[2];
int tot,head[maxn],nxt[maxn<<1],to[maxn<<1];
int dp[maxn][2];
void add(int x,int y)
{
	to[++tot]=y;
	nxt[tot]=head[x];
	head[x]=tot;
}
void dfs(int x,int f)
{
	if(x<=m)
	{
		if(opt[x])
			dp[x][0]=1;
		else
			dp[x][1]=1;
		return;
	}
	int tmp0=0,tmp1=0;
	for(int i=head[x];i;i=nxt[i])
	{
		int y=to[i];
		if(y==f)
			continue;
		dfs(y,x);
		tmp0+=dp[y][0];
		tmp1+=dp[y][1];
	}
	dp[x][0]=min(tmp0,tmp1+1);
	dp[x][1]=min(tmp0+1,tmp1);
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)
		scanf("%d",&opt[i]);
	for(int i=1;i<n;i++)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		add(x,y);
		add(y,x);
	}
	dfs(m+1,0);
	int tmp0=0,tmp1=0;
	int x=m+1;
	for(int i=head[x];i;i=nxt[i])
	{
		int y=to[i];
		tmp0+=dp[y][0];
		tmp1+=dp[y][1];
	}
	int ans=min(tmp0,tmp1);
	printf("%d\n",ans+1);
	return 0;
}