P2899 USACO08JAN Cell Phone Network G

题目描述

John想让他的所有牛用上手机以便相互交流,他需要建立几座信号塔在N块草地中。已知与信号塔相邻的草地能收到信号。给你N-1个草地(A,B)的相邻关系,问:最少需要建多少个信号塔能实现所有草地都有信号。

样例 #1

样例输入 #1

5
1 3
5 2
4 3
3 5

样例输出 #1

2

分析

最小支配集模板题

法一:贪心

#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
	int x=0,f=1;
	char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	return x*f;
}
vector<int>e[200005];
int n,tim,ans,fa[200005],dfss[200005];
bool s[200005],se[200005];
void dfs(int u,int f){
	dfss[++tim]=u;
	for(int i=0;i<e[u].size();i++){
		if(e[u][i]^f)fa[e[u][i]]=u,dfs(e[u][i],u);
	}
}
signed main(){
	n=read();
	for(int i=1,u,v;i<n;i++){
		u=read(),v=read();
		e[u].push_back(v),e[v].push_back(u);
	}
	dfs(1,0);
	for(int i=n;i;i--){
		int t=dfss[i];
		if(!s[t]){//当前点未被覆盖,既它不属于支配集,也不与支配集中的点相连
			if(!se[fa[t]])se[fa[t]]=1,++ans;//当前点的父结点不属于支配集
			s[t]=s[fa[t]]=s[fa[fa[t]]]=1;
		}
	}
	cout<<ans<<endl;
	return 0;
}

法二:树形DP

#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
	int x=0,f=1;
	char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	return x*f;
}
int n,dp[100005][5],vis[100005];
vector<int>e[100005];
void dfs(int u){
	vis[u]=1;int flag=1,tmp=INT_MAX;
	for(int i=0;i<e[u].size();i++){
		if(!vis[e[u][i]]){
			dfs(e[u][i]);
			dp[u][0]+=min(min(dp[e[u][i]][0],dp[e[u][i]][1]),dp[e[u][i]][2]);//(1)取u结点
			dp[u][2]+=min(dp[e[u][i]][0],dp[e[u][i]][1]);//(3)不取u结点,也没被子结点覆盖
			if(dp[e[u][i]][0]<=dp[e[u][i]][1]){//(2)至少选一个子结点
				dp[u][1]+=dp[e[u][i]][0];
				flag=0;
			}else{//如没取子结点,维护dp[v][0]-dp[v][1]
				dp[u][1]+=dp[e[u][i]][1];
				tmp=min(tmp,dp[e[u][i]][0]-dp[e[u][i]][1]);
			}
		}
	}
	if(flag)dp[u][1]+=tmp;//未选子结点,则必须强制换一个子结点加入,加上这个差值
	return;
}
signed main(){
	n=read();
	for(int i=1;i<n;i++){
		int u=read(),v=read();
		e[u].push_back(v),e[v].push_back(u);
	}
	for(int i=0;i<=n;i++)dp[i][0]=1,dp[i][1]=dp[i][2]=0;
	if(n==1)puts("1");
	else{
		dfs(1);
		cout<<min(dp[1][0],dp[1][1])<<endl; 
	}
	return 0;
}
posted @ 2023-06-24 13:52  alex_liu09  阅读(19)  评论(0)    收藏  举报