洛谷 P2018 消息传递 题解
总体来说是一道从下往上的DP+贪心;
设f[i]表示将消息传给i,i的子树全部接收到所能消耗的最小时间;
那么对于i的所有亲儿子节点j,我们会贪心地先给f[j]大的人传递,然后次大.....
可以证明,这样的答案一定是最优的;
然后f[i]=max(f[i],f[j]+cnt);
总的时间复杂度是O(n^2logn),可过;
但是还可以进一步优化(窝太懒了所以没写)
换根法,可以一遍dfs(nlogn)就求出所有的答案;
#include <bits/stdc++.h>
#define inc(i,a,b) for(register int i=a;i<=b;i++)
using namespace std;
int head[2010],cnt;
class littlestar{
public:
int to,nxt;
void add(int u,int v){
to=v; nxt=head[u];
head[u]=cnt;
}
}star[4010];
int n;
int f[2010];
class node{
public:
int value,pos;
};
vector<node> vec[2010];
bool cmp(node x,node y)
{
return x.value>y.value;
}
void dfs(int u,int fa)
{
for(int i=head[u];i;i=star[i].nxt){
int v=star[i].to;
if(v==fa) continue;
dfs(v,u);
vec[u].push_back((node){f[v],v});
}
sort(vec[u].begin(),vec[u].end(),cmp);
inc(j,0,(int)vec[u].size()-1){
int v=vec[u][j].pos;
f[u]=max(f[u],f[v]+j+1);
}
}
int tmp[2010];
int main()
{
scanf("%d",&n);
inc(i,2,n){
int tmp; scanf("%d",&tmp);
star[++cnt].add(tmp,i);
star[++cnt].add(i,tmp);
}
int minn=INT_MAX;
inc(i,1,n){
memset(f,0,sizeof(f));
inc(j,1,n) vec[j].clear();
dfs(i,0);
if(f[i]<minn){
tmp[0]=0;
tmp[++tmp[0]]=i;
minn=f[i];
}
else if(f[i]==minn){
tmp[++tmp[0]]=i;
}
}
printf("%d\n",minn+1);
inc(i,1,tmp[0]){
printf("%d ",tmp[i]);
}
}
/*
8
1
1
3
4
4
4
3
*/
众人皆醉我独醒,举世皆浊我独清

浙公网安备 33010602011771号