刚简单了学习了一下树形dp,我们再来做一道题联系一下吧,
题意:大致意思就是现在给你一个树,然后让你再每个节点上放士兵,每个节点的士兵都可以管辖与这个节点相连的所有的边,让你放置最小的士兵来使这个树的每条边都可以被管辖,求最小放置的士兵数。
思路:这个题大致一看就是一个dp,又是因为这是一个树。所以就是树形dp了,(这样解释是不是有点那个啥啊,哈哈)
首先我们先找状态转移方程好一个节点,假如这个节点不放士兵,那么他的孩子每个都要放置士兵,只有这样才能满足要求,再假入,这个点放置了士兵,那么他的孩子的士兵就可放可不放了,根据这个思想我们就可以列出状态转移方程,dp[root][0] += dp[i][1]; dp[root][1] += min(dp[i][0], dp[i][1]);
下面直接给出AC代码;
#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
const int maxn=1600;
#define met(a,A) memset(a,A,sizeof(a))
int dp[maxn][2],father[maxn];
bool vis[maxn];
int n;
void void_tree(int root)
{
vis[root]=1;
for(int i=1;i<=n;i++)
{
if(!vis[i]&&father[i]==root)
{
void_tree(i);
dp[root][0] += dp[i][1];
dp[root][1] += min(dp[i][0], dp[i][1]);
}
}
}
int main()
{
while(~scanf("%d",&n))
{
met(dp,0);
met(father,0);
met(vis,0);
for(int i=1;i<=n;i++)
dp[i][1]=1;
for(int i=0;i<n;i++)
{
int nn,nnn;
scanf("%d:(%d)",&nn,&nnn);
nn++;
while(nnn--)
{
int A;
scanf("%d",&A);
A++;
father[A]=nn;
}
}
void_tree(0);
printf("%d\n",min(dp[0][1],dp[0][0]));
}
return 0;
}