题目链接:https://codeforces.ml/gym/102769/problem/K
题目大意:由根节点派遣军队去占领城市,根节点有无数军队,每次只能移动一支军队,问占领完所有城市的最少时间。
思路:
由于每次只能移动一个军队,所以先优先贪心往当前节点深度最短的叶子节点移动,每次到达叶子节点,再比较是当前从根节点派兵的时间花费和不是根节点派兵的时间花费,从中取最小值。
做法:
第一遍dfs,将各个节点的边按照叶子节点的深度从小到大排序,第二次dfs统计各个叶子节点对答案的贡献。
#include <iostream> #include <cstring> #include <queue> using namespace std; const int N=1e6+7; const int M=2e6+7; int t,n; int head[N],deep[N],du[N],Ans,clik,tot; typedef pair<int,int> pll; priority_queue <pll,vector<pll>,greater<pll> > q[N]; struct Edge{ int to; int next; }pre[M]; void add(int u,int v){ pre[++tot].to=v; pre[tot].next=head[u]; head[u]=tot; } int df(int u,int fa,int h){ int res=0,ans=0; deep[u]=h; for(int i=head[u];i!=0;i=pre[i].next){ int v=pre[i].to; if(v==fa) continue; ans=df(v,u,h+1)+1; q[u].push(pll(ans,v)); res=max(res,ans); } return res; } int dfs(int u,int dep){ while(!q[u].empty()){ int v=q[u].top().second; int cost=q[u].top().first; q[u].pop(); dep=dfs(v,dep+1)+1; } if(u!=1&&du[u]==1){ Ans+=min(deep[u],dep); dep=0; } return dep; } int main(){ scanf("%d",&t); while(t--){ scanf("%d",&n); tot=0; for(int i=0;i<=n;i++){ while(!q[i].empty()){ q[i].pop(); } du[i]=deep[i]=head[i]=0; } for(int i=2;i<=n;i++){ int f; scanf("%d",&f); add(f,i),add(i,f); du[i]++,du[f]++; } Ans=0; df(1,-1,0); dfs(1,0); printf("Case #%d: %d ",++clik,Ans); } }