一棵树,n个节点,最少需要在节点上放几个士兵,能够观察到所有的边(即一条边上至少一个点选中)
dp[ u ][ j ] 表示节点u,状态为j时的把以u为根节点的子树的边全部观察的最小值,j==0表示u节点不放兵,1表示放兵,那么dp[ u ][ 0 ] = sigma(dp[ v ][ 1 ]),d[ u ][ 1 ] = sigma(min(dp[ v ][ 0 ],dp[ v ][ 1 ])),v为u的子节点。
#include <iostream>
#include <string>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
#define clr(a,b) memset((a),b,sizeof(a))
const int maxn = 1510;
typedef long long lld;
const int inf = 0x3f3f3f3f;
vector<int> vv[maxn];
int dp[maxn][2];
void DP(int u,int p)
{
dp[u][0]=0;dp[u][1]=1;
int siz=vv[u].size();
for(int i=0;i<siz;i++)
{
int v=vv[u][i];
if(v==p) continue;
DP(v,u);
dp[u][0]+=dp[v][1];
dp[u][1]+=min(dp[v][0],dp[v][1]);
}
}
int main()
{
int n;
while(~scanf("%d",&n))
{
for(int i=0;i<=n;i++) vv[i].clear();
for(int i=0;i<n;i++)
{
int u,v,m;
scanf("%d:(%d)",&u,&m);
for(int j=0;j<m;j++)
{
scanf("%d",&v);
vv[u].push_back(v);
vv[v].push_back(u);
}
}
DP(0,-1);
printf("%d\n",min(dp[0][0],dp[0][1]));
}
return 0;
}