消息传递 树形DP
非常妙的树形DP:由于n很小,我们可以枚举每一个点作为第一个节点,计算其时间花费
那么问题就转化为对于给点节点求花费时间。
通过观察,显然我们会发现先传给花费时间多的人更加合算,因为这样可以最大限度的避免
一个人还在辛苦的传递信息,另一个人却悠闲的喝下午茶(雾)的局面
所以我们可以每次都记录下对于一个节点而言,它的所有子节点的时长,
并对其排序,排序后先传给耗时最多的人,但这样传递了之后,由于耗时最多的人最先被传递,
那么这个本应耗时最多的人就不一定还是耗时最多的人了,因此我们要分别计算所有子节点
的耗时,并取max计入ans,最后dp数组即代表一旦这个节点得知消息,要多久才可以把消息传给 所有其他的人(除了传给它的那个人),即完成任务。树的结构保证了其正确性
why是ans=min(son[i]+cnt-i+1)?
因为这里为了方便是从小到大排序,又因为是优先大的
cnt-i即为还有多少个才能到它,然后+1是因为高斯这个点信息需要1的时间。
son[i]则是加上自身的时间
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define AC 1100 4 #define ACway 2500 5 #define R register int 6 #define D printf("line in %d\n",__LINE__); 7 int n; 8 int Head[AC],Next[ACway],date[ACway],tot; 9 int ans[AC],minn=INT_MAX,f[AC];//use用来存储每个节点的儿子(DFS中临时存储) 10 inline int read() 11 { 12 int x=0;char c; 13 while(isspace(c=getchar())); 14 while(c>='0' && c<='9')x=x*10+c-'0',c=getchar(); 15 return x; 16 } 17 18 inline void add(int f,int w) 19 { 20 date[++tot]=w , Next[tot]=Head[f] , Head[f]=tot; 21 date[++tot]=f , Next[tot]=Head[w] , Head[w]=tot; 22 } 23 24 void upmax(int &a,int b) 25 { 26 if(b>a)a=b; 27 } 28 29 void upmin(int &a,int b) 30 { 31 if(b<a)a=b; 32 } 33 34 void DFS(int x,int fa) 35 { 36 R now; 37 int cnt=0,son[AC];//开在DFS里面更加方便? 38 for(R i=Head[x]; i ;i=Next[i])//枚举子节点 39 { 40 now=date[i]; 41 if(now!=fa)//如果不是父亲,即为儿子 42 { 43 DFS(now,x); 44 son[++cnt]=f[now]; 45 } 46 } 47 sort(son+1,son+cnt+1); 48 for(R i=1;i<=cnt;i++) upmax(f[x],son[i]+cnt-i+1); 49 } 50 51 void pre() 52 { 53 R a; 54 n=read(); 55 for(R i=2;i<=n;i++) 56 { 57 a=read();//读入i的上级 58 add(a,i); 59 } 60 } 61 62 void work() 63 { 64 for(R i=1;i<n;i++)//枚举第一个节点 65 { 66 memset(f,0,sizeof(f)); 67 DFS(i,0); 68 ans[i]=f[i];//ans[i]存以i为第一个节点的最小耗时 69 upmin(minn,ans[i]); 70 } 71 printf("%d\n",minn+1);//还包括告诉别人的时间 72 for(R i=1;i<=n;i++) 73 if(ans[i]==minn) printf("%d ",i); 74 } 75 76 int main() 77 { 78 // freopen("in.in","r",stdin); 79 pre(); 80 work(); 81 // fclose(stdin); 82 return 0; 83 }