列表

详情


NC19914. [CQOI2009]叶子的染色

描述

给一棵m个结点的无根树,你可以选择一个度数大于1的结点作为根,然后给一些结点(根、内部结点和叶子均可)着以黑色或白色。你的着色方案应该保证根结点到每个叶子的简单路径上都至少包含一个有色结点(哪怕是这个叶子本身)。 
对于每个叶结点u,定义c[u]为从根结点从U的简单路径上最后一个有色结点的颜色。给出每个c[u]的值,设计着色方案,使得着色结点的个数尽量少。

输入描述

第一行包含两个正整数m, n,其中n是叶子的个数,m是结点总数。结点编号为1,2,…,m,其中编号1,2,… ,n是叶子。
以下n行每行一个0或1的整数(0表示黑色,1表示白色),依次为c[1],c[2],…,c[n]。
以下m-1行每行两个整数a,b(1 ≤ a < b ≤ m),表示结点a和b 有边相连。

输出描述

仅一个数,即着色结点数的最小值。

示例1

输入:

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

输出:

2

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++(g++ 7.5.0) 解法, 执行用时: 12ms, 内存消耗: 5628K, 提交时间: 2023-07-11 17:07:31

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int n,m;
int arr[N],dp[N][3];
vector<int> to[N];
void dfs(int u,int fa){
	if(u<=m){
		dp[u][arr[u]]=1;
		dp[u][1-arr[u]]=1e9;
        return;
	}
    dp[u][0]=dp[u][1]=1;
	for(auto v:to[u]){
		if(v==fa) continue;
		dfs(v,u);
		dp[u][1]+=min(dp[v][1]-1,dp[v][0]);
		dp[u][0]+=min(dp[v][0]-1,dp[v][1]);
	}
}
void solve(){
	cin>>n>>m;
	for(int i=1;i<=m;i++) cin>>arr[i];
	for(int i=1;i<n;i++){
		int a,b;
		cin>>a>>b;
		to[a].push_back(b);
		to[b].push_back(a);
	}
    int ans=1e9;
    for(int i=m+1;i<=m+1;i++){
	   dfs(i,0);
	   ans=min(dp[i][0],dp[i][1]);
    }
    cout<<ans<<"\n";
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int t=1;
// 	cin>>t;
	while(t--) solve();
}

C++14(g++5.4) 解法, 执行用时: 10ms, 内存消耗: 3168K, 提交时间: 2020-01-30 11:22:23

#include<bits/stdc++.h>
using namespace std;
#define see(x) cerr<<(#x)<<"="<<x<<endl;
typedef long long ll;
const int N=1e5+100;

vector<int>edge[N];
int dp[N][2];

void dfs(int x,int fa) {
    for(auto v:edge[x]) if(v!=fa) {
        dfs(v,x);
        dp[x][0]+=min(dp[v][0]-1,dp[v][1]);
        dp[x][1]+=min(dp[v][1]-1,dp[v][0]);
    }
}

int main() {
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        dp[i][1]=dp[i][0]=1;

    for(int i=1,x;i<=m;i++) {
        scanf("%d",&x);
        dp[i][!x]=1e9;
    }
    for(int i=1,u,v;i<n;i++) {
        scanf("%d%d",&u,&v);
        edge[u].push_back(v);
        edge[v].push_back(u);
    }
    dfs(n,0);
    cout<<min(dp[n][0],dp[n][1]);
}

C++11(clang++ 3.9) 解法, 执行用时: 34ms, 内存消耗: 24556K, 提交时间: 2020-04-03 14:36:01

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+100;
vector<int>G[N];
int dp[N][2],col[N];
int m,n;
void dfs(int x,int fa)
{
	if(x<=n)
	{
		dp[x][col[x]]=1;
		dp[x][col[x]^1]=0x3f3f3f3f;
		return;
	}
	dp[x][0]=dp[x][1]=1;
	for(int v:G[x])
	{
		if(v==fa) continue;
		dfs(v,x);
		dp[x][0]+=min(dp[v][0]-1,dp[v][1]);
		dp[x][1]+=min(dp[v][1]-1,dp[v][0]);
	}
}
int main()
{
	cin>>m>>n;
	for(int i=1;i<=n;i++)
	cin>>col[i];
	for(int i=1;i<m;i++)
	{
		int x,y;
		cin>>x>>y;
		G[x].push_back(y);
		G[y].push_back(x);
	}
	dfs(m,0);
	cout<<min(dp[m][0],dp[m][1])<<endl;
	return 0;
}

上一题