题目:洛谷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;
}