luogu#P2016 战略游戏

题意:

给出一棵有 \(N\) 个节点的树,节点编号 \(0\) ~ \(N-1\) 。如果在一个节点上放置一个士兵,那么该节点及与该节点相连的所有节点都可以被瞭望到。求瞭望到所有节点所需的最少的士兵数。

解法:

树形dp

\(f[i][j]\) = 节点 \(i\) 选(\(j=1\))不选(\(j=0\))的最少需要的士兵

因为对于一个节点 \(i\) ,如果它不选,那么必须选与它相连的点的其中一个,则:

f[x][1]+=min(f[v][0],f[v][1]); //设v是与x相邻的点
f[x][0]+=f[v][1];

因为没有给出树根,所以要手动求出。

感觉跟没有舞会的上司差不多,居然还是一道蓝题

#include<iostream>
#define N 1505
using namespace std;
struct Edge{int next,to;}edge[N<<1];
int n_e,head[N],n,root;
int f[N][2];
bool rt[N];

void dp(int x);
void addedge(int from,int to);
void init();
int main()
{
	init();
	dp(root);
	cout<<min(f[root][1],f[root][0]);
	
	return 0;
}
void init()
{
	cin>>n;
	for(int i=0;i<n;i++)
	{
		int id,num,v;
		cin>>id>>num;
		f[i][1]=1;
		for(int j=0;j<num;j++)
		{
			cin>>v;
			rt[v]=1;
			addedge(id,v);
		}
	}
	for(int i=0;i<n;i++)
		if(!rt[i])
		{
			root=i;
			break;
		}
}
void addedge(int from,int to)
{
	edge[++n_e].next=head[from];
	edge[n_e].to=to;
	head[from]=n_e;
}
void dp(int x)
{
	for(int i=head[x];i;i=edge[i].next)
	{
		int v=edge[i].to;
		dp(v);
		f[x][1]+=min(f[v][1],f[v][0]);
		f[x][0]+=f[v][1];
	}	
}
posted @ 2019-10-21 22:01  nenT  阅读(107)  评论(0)    收藏  举报