题目传送门sxazr
由题意得,本题所描述的图是一棵树,让你在树上求解最值,我们可以用树形dp来解决。
每一个点是否放兵可以看成一种决策,一条路两头至少要有一个士兵,
设f[x][1]表示x点放士兵时,以x点为根的子树需要的最少士兵数;f[x][0]表示x点不放士兵时,以x为根的子树需要的最少士兵数。
①当x点不放士兵时,它的所有儿子必须放,f [x] [0]+=∑ f [y] [1] (y为x的儿子);
②当x点放士兵时,它的儿子放不放都行,但应取最小值,f [x] [1]+=min( f [y] [1] , f [y] [0] )。
初始化f[x][0]=0,f[x][1]=1。
ans=min( f [root] [0] , f [root] [1] ).
本人属超级蒟蒻一枚
代码如下
#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
int n,f[1510][2],vis[1511];
vector<int>q[1510];
void sx(int x)
{
f[x][1]=1;
if(!q[x].size()) return;
for(int j=0;j<q[x].size();j++){
int y=q[x][j];
sx(y);
f[x][0]+=f[y][1];
f[x][1]+=min(f[y][0],f[y][1]);
}
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++){
int u,k;
scanf("%d%d",&u,&k);
for(int j=1;j<=k;j++){
int a;
scanf("%d",&a);
q[u].push_back(a);
vis[a]=1;
}
}
int root=0; //注意从0开始
while(vis[root]) root++; //找到根节点
sx(root);
cout<<min(f[root][1],f[root][0]);
return 0;
}