题目描述
2020 年,人类在火星上建立了一个庞大的基地群,总共有 nn 个基地。起初为了节约材料,人类只修建了 n-1n−1 条道路来连接这些基地,并且每两个基地都能够通过道路到达,所以所有的基地形成了一个巨大的树状结构。如果基地 AA 到基地 BB 至少要经过 dd 条道路的话,我们称基地A到基地B的距离为 dd。
由于火星上非常干燥,经常引发火灾,人类决定在火星上修建若干个消防局。消防局只能修建在基地里,每个消防局有能力扑灭与它距离不超过 22 的基地的火灾。
你的任务是计算至少要修建多少个消防局才能够确保火星上所有的基地在发生火灾时,消防队有能力及时扑灭火灾。
输入格式
输入文件的第一行为 nn(1 \leq n \leq 10001≤n≤1000),表示火星上基地的数目。接下来的 n-1n−1 行每行有一个正整数,其中文件第 ii 行的正整数为 a_iai,表示从编号为 ii 的基地到编号为 a_iai 的基地之间有一条道路,为了更加简洁的描述树状结构的基地群,有 a_i\lt iai<i。
输出格式
仅有一个正整数,表示至少要设立多少个消防局才有能力及时扑灭任何基地发生的火灾。
树形dp解法
#include<iostream>
#include<cstring>
using namespace std;
const int maxn=1e3+5;
const int INF=1e9;
int head[maxn];
struct node{
int to,next;
}edge[maxn<<1];
int cnt=0;
void add_edge(int from,int to)
{
edge[cnt].to=to;
edge[cnt].next=head[from];
head[from]=cnt++;
}
int f[maxn][5];
void dfs(int root,int pre)
{
int sum2=0,sum3=0,tot=0;
for(int i=head[root];i!=-1;i=edge[i].next)
{
int to=edge[i].to;
if(to!=pre)
{
dfs(to,root);
sum2+=f[to][2];
sum3+=f[to][3];
tot++;
}
}
if(!tot)
{
f[root][0]=1;f[root][1]=1;f[root][2]=1;
return;
}
f[root][0]=1;f[root][1]=INF;f[root][2]=INF;
for(int i=head[root];i!=-1;i=edge[i].next)
{
int to=edge[i].to;
if(to!=pre)
{
f[root][0]+=f[to][4];
f[root][1]=min(f[root][1],f[to][0]+sum3-f[to][3]);
f[root][2]=min(f[root][2],f[to][1]+sum2-f[to][2]);
f[root][3]+=f[to][2];
f[root][4]+=f[to][3];
}
}
for(int i=1;i<5;i++)
{
f[root][i]=min(f[root][i],f[root][i-1]);
}
}
int main()
{
int n;cin>>n;
memset(head,-1,sizeof(head));
for(int i=1;i<n;i++)
{
int now;cin>>now;
add_edge(i+1,now);
add_edge(now,i+1);
}
dfs(1,0);
cout<<f[1][2]<<endl;
}
贪心:
#include<iostream> #include<cstring> #include<algorithm> using namespace std; const int maxn=1e3+5; const int INF=1e9; int dep[maxn]; int fa[maxn]; int dis[maxn]; int head[maxn],id[maxn]; struct node{ int to,next; }edge[maxn<<1]; int cnt=0; bool cmp(int a,int b) { return dep[a]>dep[b]; } void add_edge(int from,int to) { edge[cnt].to=to; edge[cnt].next=head[from]; head[from]=cnt++; } void dfs(int root,int pre) { dep[root]=dep[pre]+1; for(int i=head[root];i!=-1;i=edge[i].next) { int to=edge[i].to; if(to!=pre) { fa[to]=root; dfs(to,root); } } } int main() { int n;cin>>n; memset(head,-1,sizeof(head)); for(int i=1;i<n;i++) { int from;cin>>from; add_edge(from,i+1); add_edge(i+1,from); id[i]=i; } id[n]=n; dfs(1,0); sort(id+1,id+1+n,cmp); memset(dis,0x3f,sizeof(dis)); int ans=0; for(int i=1;i<=n;i++) { int w=id[i]; dis[w]=min(dis[w],dis[fa[w]]+1); dis[w]=min(dis[w],dis[fa[fa[w]]]+2); if(dis[w]>2) { ans++; int grf=fa[fa[w]]; dis[grf]=0; dis[fa[grf]]=min(dis[fa[grf]],1); dis[fa[fa[grf]]]=min(dis[fa[fa[grf]]],2); } } cout<<ans<<endl; }