战略游戏(树形dp)

题目传送门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;
}

猜你喜欢

转载自blog.csdn.net/qq_42920137/article/details/88075671