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;
}

浙公网安备 33010602011771号