您的位置:首页 > 产品设计 > UI/UE

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

2014-10-30 17:20 447 查看
题意:给你一个有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!输入:441 21 31 4201 22 32 73 43 144 54 195 67 87 99 1010 1110 1212 1314 1515 1615 1717 1819 2071 22 33 44 55 66 751 22 33 44 5输出:1 1 44 14 102 2 61 2 5
                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: