题意:给你一棵边权都为1的树,要求选择互不相交的若干条路径,这些路径包含有所有点。
在每一条路径上选择一条边,放置一个动点,设置一个方向,它开始在该路径上来回运动,速度为1。每个点上都有一个停表,当有一个动点经过这个点时它清零。设res_i表示i停表的历史最大显示时间。设得res_1,res_2,res_3,……序列的字典序最小。
n<=100。(数据范围有时候是唬人的)
标程:
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=105; 4 int n,u[N],v[N],head[N],rd[N],cnt,To[N]; 5 double ans[N]; 6 struct node{int to,next;}num[N*2]; 7 void add(int x,int y) 8 {num[++cnt].to=y;num[cnt].next=head[x];head[x]=cnt;} 9 void dfs(int x,int fa,double lst) 10 { 11 double e=2.0/rd[x];//注意用2.0/而不是2/! 12 for (int i=head[x];i;i=num[i].next) 13 if (num[i].to!=fa) 14 { 15 lst+=e;while (lst>2) lst-=2; 16 int id=(i+1)/2; 17 if (lst<=1) To[id]=x,ans[id]=lst; 18 else To[id]=num[i].to,ans[id]=lst-1; 19 dfs(num[i].to,x,lst+1); 20 } 21 } 22 int main() 23 { 24 scanf("%d",&n); 25 for (int i=1;i<n;i++) scanf("%d%d",&u[i],&v[i]),add(u[i],v[i]),add(v[i],u[i]),rd[u[i]]++,rd[v[i]]++; 26 dfs(1,-1,0); 27 printf("%d\n",n-1); 28 for (int i=1;i<n;i++) printf("1 %d %d %d %.8lf\n",i,u[i]+v[i]-To[i],To[i],ans[i]); 29 return 0; 30 }
易错点:1.注意double的除法。
2.注意lst表示到动点到儿子的距离。往下一层dfs的时候注意变更。
题解:贪心+构造
发现当每一条边都独立为一条路径时,经过路径上每一个点的时间间隔是最小的。
因此发现某动点一来一回时间间隔为2,对于i点的停表,历史最大时间为2/deg[i]。一定可以构造出来。
dfs按照树的结构构造一下即可。