蒟蒻第一次写树形DP……
有的没的
在树形DP中,我们一般以节点从深到浅(子树从小到大)的顺序作为DP的“阶段”。
大多时候,我们采用递归的方式实现树形DP,对于每个节点x,我们先递归他的子节点,在回溯时,再从子节点向节点x进行转移。
我们来看看这道超水的树形DP
题目描述
Bob喜欢玩电脑游戏,特别是战略游戏。但是他经常无法找到快速玩过游戏的办法。现在他有个问题。他要建立一个古城堡,城堡中的路形成一棵树。他要在这棵树的结点上放置最少数目的士兵,使得这些士兵能了望到所有的路。注意,某个士兵在一个结点上时,与该结点相连的所有边将都可以被了望到。
请你编一程序,给定一树,帮Bob计算出他需要放置最少的士兵。
输入格式
输入文件中数据表示一棵树,描述如下: 第一行 N,表示树中结点的数目。 第二行至第N+1行,每行描述每个结点信息,依次为:该结点标号i,k(后面有k条边与结点I相连),接下来k个数,分别是每条边的另一个结点标号r1,r2,…,rk。 对于一个n(0
输出格式
输出文件仅包含一个数,为所求的最少的士兵数目。
样例数据
input
4
0 1 1
1 2 2 3
2 0
3 0
output
1
Solution
表示是否选i这个节点最少的士兵人数
//By Bibi
/// .-~~~~~~~~~-._ _.-~~~~~~~~~-.
/// __.' ~. .~ `.__
/// .'// \./ \\`.
/// .'// | \\`.
/// .'// .-~"""""""~~~~-._ | _,-~~~~"""""""~-. \\`.
/// .'//.-" `-. | .-' "-.\\`.
/// .'//______.============-.. \ | / ..-============.______\\`.
/// .'______________________________\|/______________________________`.
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define dep(i,a,b) for(int i=a;i>=b;--i)
using namespace std;
const int MAXN=1501;
int inline read(){
int sum=0,flag=1;
char c;
for(;c<'0'||c>'9';c=getchar())if(c=='-') flag=-1;
for(;c>='0'&&c<='9';c=getchar())sum=(sum<<1)+(sum<<3)+c-'0';
return sum*flag;
}
int n;
struct edge{
int y,next;
}e[MAXN<<1];
int f[MAXN][2];
int link[MAXN];
int tot;
int num[MAXN];
void inline insert(int x,int y){
e[++tot].y=y;e[tot].next=link[x];link[x]=tot;
}
void inline init(){
n=read();
int x,y;
rep(i,1,n){
x=read();
num[x]=read();
rep(j,1,num[x]){
y=read();
insert(x,y);
insert(y,x);
}
}
}
void inline DP(int x,int fa){
f[x][1]=1;
for(int i=link[x];i;i=e[i].next){
int y=e[i].y;
if(y==fa) continue;
DP(y,x);
f[x][0]+=f[y][1];
f[x][1]+=min(f[y][0],f[y][1]);
}
}
int main(){
init();
DP(0,-1);
printf("%d",min(f[0][0],f[0][1]));
return 0;
}