题目:洛谷P4220、UOJ#347。
题目大意:给你三棵树,要你找到两个点,使其在三棵树上的最短路径和最大。
解题思路:正解是边分治,不会啊。于是本题可以随机化。
具体是,每次随机一个根,然后暴力找到一个点,该点在三棵树上到根距离和最大。然后以这个点为根继续做,迭代几遍。再重新随机一个根,以此类推(已经求过的根不需要再求)。
然后卡一下时间,在3000ms左右结束随机,输出答案即可。
注意当n小于8000时直接暴力,否则随机化可能会死循环。
于是n大的点,每个点都卡在3000ms左右。
C++ Code:
#include<bits/stdc++.h> #define N 100005 #define TIME_LIMIT 2900 #define CLK (double)clock()/(double)CLOCKS_PER_SEC*1000.0 #define ll long long int n; bool ur[N]; ll ans=0; inline int readint(){ int c=getchar(); for(;!isdigit(c);c=getchar()); int d=0; for(;isdigit(c);c=getchar()) d=(d<<3)+(d<<1)+(c^'0'); return d; } inline ll debian(){ int c=getchar(); for(;!isdigit(c);c=getchar()); ll d=0; for(;isdigit(c);c=getchar()) d=(d<<3)+(d<<1)+(c^'0'); return d; } struct Graph{ int cnt,head[N]; ll dis[N]; struct edge{ int to,nxt; ll dis; }e[N<<1]; inline void addedge(int u,int v,ll w){ e[++cnt]=(edge){v,head[u],w}; head[u]=cnt; e[++cnt]=(edge){u,head[v],w}; head[v]=cnt; } Graph():cnt(0){ memset(head,0,sizeof head); } void dfs(int now,int pre){ for(int i=head[now];i;i=e[i].nxt) if(e[i].to!=pre){ dis[e[i].to]=dis[now]+e[i].dis; dfs(e[i].to,now); } } }G[3]; void not_rand(){ for(int i=1;i<=n;++i){ G[0].dis[i]=G[1].dis[i]=G[2].dis[i]=0; G[0].dfs(i,0),G[1].dfs(i,0),G[2].dfs(i,0); for(int j=1;j<=n;++j){ ll now=G[0].dis[j]+G[1].dis[j]+G[2].dis[j]; if(now>ans)ans=now; } } printf("%lld ",ans); } int main(){ memset(ur,0,sizeof ur); srand(20170607); n=readint(); for(int i=1;i<n;++i){ int u=readint(),v=readint(); ll w=debian(); G[0].addedge(u,v,w); } for(int i=1;i<n;++i){ int u=readint(),v=readint(); ll w=debian(); G[1].addedge(u,v,w); } for(int i=1;i<n;++i){ int u=readint(),v=readint(); ll w=debian(); G[2].addedge(u,v,w); } double BEG=CLK; if(n<=8000){not_rand();return 0;} while(CLK-BEG<=TIME_LIMIT){ int rt=(ll)rand()*rand()%n+1; while(ur[rt]&&CLK-BEG<=TIME_LIMIT)rt=(ll)rand()*rand()%n+1; for(int i=1;i<10;++i){ if(ur[rt])break; ur[rt]=1; G[0].dis[rt]=G[1].dis[rt]=G[2].dis[rt]=0; G[0].dfs(rt,0),G[1].dfs(rt,0),G[2].dfs(rt,0); ll mx=0; for(int j=1;j<=n;++j){ ll now=G[0].dis[j]+G[1].dis[j]+G[2].dis[j]; if(now>ans)ans=now; if(!ur[j]&&now>mx){ mx=now,rt=j; } } } } printf("%lld ",ans); return 0; }