https://vjudge.net/problem/POJ-1463
题意:一棵树,放哨兵站岗,如果有一个点放置了兵,那么与其相连的所有点都能被监视,求树的所有点都被监视且放置哨兵数目最少。
思路:dp[maxn][2]
dp[i][0]表示不选取该点,dp[i][1]表示选取该点。
若该点不选取,则其子节点必须都被选取。
若该点选取,则应选取min(dp[son][0],dp[son][1]);
类似的题目:https://blog.youkuaiyun.com/qq_38924883/article/details/82988994
#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
#define maxn 1505
using namespace std;
int dp[maxn][2],degree[maxn],vis[maxn];
vector<int>v[maxn];
void dfs(int u)
{
vis[u]=1;
for(int i=0;i<v[u].size();i++)
{
if(vis[v[u][i]]) continue;
dfs(v[u][i]);
dp[u][0]+=dp[v[u][i]][1];
dp[u][1]+=min(dp[v[u][i]][0],dp[v[u][i]][1]);
}
}
int main()
{
///ios::sync_with_stdio(false);
int n;
while(cin>>n)
{
memset(degree,0,sizeof(degree));
memset(vis,0,sizeof(vis));
for(int i=0;i<maxn;i++)
v[i].clear();
int u,to,m;
for(int i=0;i<n;i++)
{
dp[i][0]=0;dp[i][1]=1;
scanf("%d:(%d)",&u,&m);
for(int i=0;i<m;i++)
{
scanf("%d",&to);
v[u].push_back(to);
degree[to]++;
}
}
int root;
for(int i=0;i<n;i++)
{
if(degree[i]==0)
{
root=i;
break;
}
}
dfs(root);
cout<<min(dp[root][0],dp[root][1])<<endl;
}
return 0;
}