洛谷P10723 [GESP202406 七级] 黑白翻转

题目

传送门

思路

借鉴了题解区的第一篇题解

怎么找到最少执行的操作次数

执行两个黑点中的白点即可

怎么找到两个黑点中的白点

因为是树,我们可以取一个黑点dfs,只要寻找黑点,然后返回1,就可以标记中间的白点为执行,也就是ans++

代码

高清有注释

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,ans=0;
int a[N];
bool vis[N];
vector<int>v[N];
bool dfs(int x){ 
	if(v[x].size()==0&&a[x]==0){//为白点的叶子结点 
		vis[x]=1;
		return 0;
	}
	if(v[x].size()==0&&a[x]==1){//为黑点的叶子结点 
		vis[x]=1;
		return 1;
	} 
	bool f=0;
	for(int i=0;i<v[x].size();i++){//遍历相邻的边 
		int u=v[x][i];
		if(vis[u]==0){//没被标记 
			vis[u]=1;
			f|=dfs(u); //只要有1即可 
		}
	}
	if(a[x]==0){
		if(f==1)ans++;//执行白点变黑点 
	} 
	else{
		f=1;//本身就是黑点 
	}
	return f;//返回情况 
} 
int main(){
	std::ios::sync_with_stdio(false);
	std::cin.tie(0);
	std::cout.tie(0);
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	for(int i=1;i<n;i++){
		int x,y;
		cin>>x>>y;
		v[x].push_back(y);
		v[y].push_back(x);
	}
	int st=-1;
	for(int i=1;i<=n;i++){
		if(a[i]==1){//寻找黑点 
			st=i;
			break;
		}
	}
	if(st==-1){//没找到黑点直接输出0 
		cout<<0;
		return 0;
	}
	vis[st]=1;//开局要标记 
	dfs(st);
	cout<<ans;
	return 0;
} 

高清无注释

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,ans=0;
int a[N];
bool vis[N];
vector<int>v[N];
bool dfs(int x){ 
	if(v[x].size()==0&&a[x]==0){
		vis[x]=1;
		return 0;
	}
	if(v[x].size()==0&&a[x]==1){
		vis[x]=1;
		return 1;
	} 
	bool f=0;
	for(int i=0;i<v[x].size();i++){
		int u=v[x][i];
		if(vis[u]==0){
			vis[u]=1;
			f|=dfs(u); 
		}
	}
	if(a[x]==0){
		if(f==1)ans++;
	} 
	else{
		f=1;
	}
	return f;
} 
int main(){
	std::ios::sync_with_stdio(false);
	std::cin.tie(0);
	std::cout.tie(0);
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	for(int i=1;i<n;i++){
		int x,y;
		cin>>x>>y;
		v[x].push_back(y);
		v[y].push_back(x);
	}
	int st=-1;
	for(int i=1;i<=n;i++){
		if(a[i]==1){
			st=i;
			break;
		}
	}
	if(st==-1){
		cout<<0;
		return 0;
	}
	vis[st]=1;
	dfs(st);
	cout<<ans;
	return 0;
} 

完结撒花QWQ

posted @ 2026-08-27 22:25  陈晨2011  阅读(7)  评论(0)    收藏  举报