ZOJ 3820Building Fire Stations 树的最长链性质(拓展)

来源:互联网 发布:微信好友数据分析软件 编辑:程序博客网 时间:2024/06/07 04:49

题意:

给你一个有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


0 0
原创粉丝点击