题意:
给你一个有n个点的树,n是2个点以上,从中找出两个点作为“消防点”,每个点距离这两个点都有个距离,取短的那个距离叫做“消防距离”,问怎样设置两个点,所有点“消防距离”的最大值最小。
树是有最长链的,最长链上的中点距离其他点的距离最大值是最小的。但是有两个点可以加啊,怎么办?就考虑把树劈开,从最长链的中点处劈开,对于两半各取最长链的中点。对于劈开有歧义的就多找几个点劈几次取最优值。
代码:
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int maxn = 222222;
struct Edge{
int u,v,nxt;
Edge(int u=0,int v=0,int nxt=0):u(u),v(v),nxt(nxt){}
}edge[maxn<<1];
int head[maxn],tot;
void init(int n){
tot=0;
for(int i=0;i<=n;i++)
head[i]=-1;
}
void add(int u,int v){
edge[tot]=Edge(u,v,head[u]);
head[u]=tot++;
edge[tot]=Edge(v,u,head[v]);
head[v]=tot++;
}
int q[maxn],vis[maxn],pre[maxn],path[maxn];
void clrvis(int n,int u=0){
for(int i=0;i<=n;i++)
vis[i] = 0;
vis[u]=1;
}
int bfs(int u){
int tail=0,v,farestv=u;
q[tail++]=u;
pre[u]=-1;
vis[u]=1;
for(int i=0;i<tail;i++){
u=q[i];
for(int e=head[u];~e;e=edge[e].nxt){
v=edge[e].v;
if(vis[v]) continue;
vis[v]=vis[u]+1;
pre[v]=u;
if(vis[farestv]<vis[v]) farestv=v;
q[tail++]=v;
}
}
return farestv;
}
int getPath(int t){
int n=0;
path[++n]=t;
while(~pre[t]){
path[++n]=pre[t];
t=pre[t];
}
return n;
}
void getans(int n){
int s,t,pathn,ansdis,ansu,ansv;
// Ans centerAns = cutAndGetAns(n,n+1);
clrvis(n,n+1);
s=bfs(1);
clrvis(n,n+1);
t=bfs(s);
pathn = getPath(t);
if(pathn&1){/**odd number points in d*/
/**
u-center|v
*/
int center = path[pathn/2+1],u=path[pathn/2],v=path[pathn/2+2];
clrvis(n,v);
s=bfs(u);
clrvis(n,v);
t=bfs(s);
int un = getPath(t);
ansu = path[un/2+1];
ansdis = un/2;
clrvis(n,center);
s=bfs(v);
clrvis(n,center);
t=bfs(s);
int vn = getPath(t);
ansv = path[vn/2+1];
ansdis = max(ansdis,vn/2);
/**
u|center-v
*/
clrvis(n,u);
s=bfs(v);
clrvis(n,u);
t=bfs(s);
un = getPath(t);
int ansu2 = path[un/2+1];
int ansdis2 = un/2;
clrvis(n,center);
s=bfs(u);
clrvis(n,center);
t=bfs(s);
vn = getPath(t);
int ansv2 = path[vn/2+1];
ansdis2 = max(ansdis2,vn/2);
/**
get the optional answer
*/
if(ansdis>ansdis2){
ansu = ansu2;
ansv = ansv2;
}
}else{/**even number points in d*/
int u=path[pathn/2],v=path[pathn/2+1];
clrvis(n,v);
s=bfs(u);
clrvis(n,v);
t=bfs(s);
int un = getPath(t);
ansu = path[un/2+1];
ansdis = un/2;
clrvis(n,u);
s=bfs(v);
clrvis(n,u);
t=bfs(s);
int vn = getPath(t);
ansv = path[vn/2+1];
ansdis = max(ansdis,vn/2);
}
printf("%d %d %d\n",ansdis,ansu,ansv);
}
int main(){
// freopen("data.in","r",stdin);
int T,n,u,v;
scanf("%d",&T);
while(T--){
scanf("%d",&n);
init(n);
for(int i=1;i<n;i++){
scanf("%d%d",&u,&v);
add(u,v);
}
getans(n);
}
return 0;
}
spj!
输入:
4
4
1 2
1 3
1 4
20
1 2
2 3
2 7
3 4
3 14
4 5
4 19
5 6
7 8
7 9
9 10
10 11
10 12
12 13
14 15
15 16
15 17
17 18
19 20
7
1 2
2 3
3 4
4 5
5 6
6 7
5
1 2
2 3
3 4
4 5
输出:
1 1 4
4 14 10
2 2 6
1 2 5