题意:
给出一棵有 \(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];
}
}
原文地址:https://www.cnblogs.com/nenT/p/11716605.html
时间: 2024-10-12 07:13:51