战略游戏(树形DP)

洛咕

题意:在一棵树的结点上放置最少数目的士兵,使得这些士兵能瞭望到所有的路.注意,某个士兵在一个结点上时,与该结点相连的所有边将都可以被瞭望到.

分析:很经典的一道节点01型树上背包问题.对于每一个节点只有两种情况,选(1)或者不选(0).所以状态转移只有两种:

(f[u][0]+=f[v][1]),若父节点u不选,则子节点v都要选.

(f[u][1]+=min(f[v][0],f[v][1])),若父节点u被选了,则子节点v取最优情况.

初始化(f[u][1]=1,f[u][0]=0).

#include<bits/stdc++.h>
using namespace std;
inline int read(){
   int s=0,w=1;char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getchar();}
   return s*w;
}
int n,root;
int visit[1505],f[1505][2];
vector<int> q[1505];
void dfs(int u){
    f[u][1]=1;f[u][0]=0;
    for(int i=0;i<q[u].size();i++){
		int v=q[u][i];
		dfs(v);
		f[u][0]+=f[v][1];
		f[u][1]+=min(f[v][0],f[v][1]);
    }
    return;
}
int main(){
    n=read();
    for(int i=1;i<=n;i++){
		int num=read(),size=read();
		for(int j=1;j<=size;j++){
	    	int son=read();
	    	q[num].push_back(son);
	    	visit[son]=1;//标记是子节点
		}//存边,根据个人习惯
    }
    for(int i=0;i<n;i++)//找根
    	if(!visit[i]){root=i;break;}
    dfs(root);
    printf("%d
",min(f[root][0],f[root][1]));
    return 0;
}

原文地址:https://www.cnblogs.com/PPXppx/p/10543143.html