题目链接:
POJ-3659
题意: 给你一棵树,在树上装一些信号搭,有信号搭的节点可以使得自己和相邻的节点有信号,问最小安装多少个节点使得树上任意一个点都能有信号。
题解:这个就是求最小支配集,用树形dp一下就好。
dp[u][0] 代表不取i节点,靠子节点覆盖,
dp[u][1]代表去u节点 ,
dp[u][2]代表不取u节点,靠父节点覆盖
代码如下:
#include<iostream>
#include<vector>
#include<cstdio>
using namespace std;
int a[60006];
int dp[60006][3];//dp[u][0] 代表不取i节点,靠子节点覆盖,dp[u][1]代表去u节点 ,dp[u][2]代表不取u节点,靠父节点覆盖
int vis[60006];
vector<int>v[60006];
void dfs(int u,int fa ,int sum)
{
if(v[u].size()==0&&sum)
{
dp[u][0]=0;
dp[u][1]=1;
return ;
}
dp[u][0]=0;dp[u][1]=1;dp[u][2]=0;
int flag=0;
for(int i=0;i<v[u].size();i++)
{
int vv=v[u][i];
if(vv==fa)
continue;
dfs(vv,u,sum+1);
if(dp[vv][0]>=dp[vv][1])
{
dp[u][0]+=dp[vv][1];
flag=1;
}
else
{
dp[u][0]+=dp[vv][0];
}
dp[u][1]+=min(dp[vv][2],min(dp[vv][0],dp[vv][1]));
dp[u][2]+=min(dp[vv][0],dp[vv][1]);
}
if(!flag)//至少保证有一个子节点是取了的,如果都没取,加一个节点。
dp[u][0]++;
return ;
}
int main()
{
int n,m,u,vv,t;
cin>>n;
if(n==1){
cout<<1<<endl;
return 0;
}
for(int i=0;i<=n;i++)
v[i].clear();
for(int i=1;i<n;i++)
{
scanf("%d%d",&u,&vv);
v[u].push_back(vv);
v[vv].push_back(u);
}
dfs(1,-1,0);
int ans=min(dp[1][1],dp[1][0]);
cout<<ans<<endl;
return 0;
}