题目
题目描述
一棵树上有K只羊,树是一个没有环的简单连通图。这棵树有N个节点,用1到N表示。树的每个节点最多只能住一只羊。Soaring意识到,狼迟早会学会爬树。
为了保护羊,Soaring决定安排一些牧羊人住在在树中某些节点上,以确保每只羊至少被一个牧羊人保护。众所周知,每个牧羊人都会保护所有离他最近的羊,且只会保护它们。羊和牧羊人的距离等于两者之间简单路径的边数包含绵羊的节点和包含shepherd的节点之间唯一路径上的节点。此外,牧羊人可以跟羊住在一起,当然,这种情况下,牧羊人只保护这只羊。
计算最少需要放置多少个牧羊人,使得每只羊都至少被一个牧羊人保护。另外,输出一种放置方案。
数据范围
n ≤ 500000 n\leq500000 n≤500000
题解
题目大意
给出一棵树,一些点染了色 ,每个点可以覆盖所有离它最近的染色点,问最少需要多少个才能覆盖所有染色点,和具体放置方案
题目分析
考虑贪心
先预处理每个点到最近的染色点的距离 d i s i dis_i disi,这个可以两遍 d f s dfs dfs解决。然后每次找到一个深度最深的点,然后暴力往上跳,找到一个最浅的能覆盖它的点,然后输出,随即删点。删点的原则是 d i s y + 1 = d i s x dis_y+1=dis_x disy+1=disx,这样能保证 x x x一定可以覆盖到 y y y可以覆盖的点。由于每个点只会删一次,时间复杂度 O ( n ) O(n) O(n)
Code
#include<cstdio>
#include<algorithm>
#define inf 2147483600
#define N 500005
using namespace std;
struct node
{
int head,next,to;
}a[N<<1];
struct node1
{
int id,deep;
}p[N];
int n,m,x,y,ans,tot,sheep[N],deep[N],ans1[N],fa[N];
bool b[N],bj[N];
void add(int x,int y)
{
a[++tot].to=y;
a[tot].next=a[x].head;
a[x].head=tot;
}
void getlen1(int now,int fa)
{
sheep[now]=min(sheep[now],sheep[fa]+1);
if (b[now]) sheep[now]=0;
for (int i=a[now].head;i;i=a[i].next)
{
if (a[i].to==fa) continue;
getlen1(a[i].to,now);
}
}
void getlen2(int now,int fa)
{
if (b[now]) sheep[now]=0;
for (int i=a[now].head;i;i=a[i].next)
{
if (a[i].to==fa) continue;
getlen2(a[i].to,now);
sheep[now]=min(sheep[now],sheep[a[i].to]+1);
}
}
void dfs(int now)
{
deep[now]=deep[fa[now]]+1;
for (int i=a[now].head;i;i=a[i].next)
{
if (a[i].to==fa[now]) continue;
fa[a[i].to]=now;
dfs(a[i].to);
}
}
bool cmp(node1 x,node1 y) {return x.deep>y.deep;}
int up(int now)
{
int len=0;
while (len+1==sheep[fa[now]]&&!bj[fa[now]]) ++len,now=fa[now];
return now;
}
void flag(int now,int fa)
{
bj[now]=true;
for (int i=a[now].head;i;i=a[i].next)
{
if (a[i].to==fa||bj[a[i].to]) continue;
if (sheep[a[i].to]==sheep[now]-1) flag(a[i].to,now);
}
}
int main()
{
freopen("shepherd.in","r",stdin);
freopen("shepherd.out","w",stdout);
scanf("%d%d",&n,&m);
for (int i=1;i<n;++i)
scanf("%d%d",&x,&y),add(x,y),add(y,x);
for (int i=1;i<=m;++i)
scanf("%d",&p[i].id),b[p[i].id]=true;
for (int i=0;i<=n;++i)
sheep[i]=inf;
getlen2(1,0);
getlen1(1,0);
sheep[0]=-1;
dfs(1);
for (int i=1;i<=m;++i)
p[i].deep=deep[p[i].id];
sort(p+1,p+m+1,cmp);
for (int i=1;i<=m;++i)
{
if (!bj[p[i].id])
{
int num=up(p[i].id);
flag(num,0);
ans1[++ans]=num;
}
}
printf("%d\n",ans);
for (int i=1;i<=ans;++i)
printf("%d ",ans1[i]);
fclose(stdin);
fclose(stdout);
return 0;
}