POJ3099 Go Go Gorelians

树的中心

题目传送门

题目大意:给你一棵树,求其中心。
当然,这只是大意,题目中有N多坑点等你发现哟!

思路的话就是搜索两遍求出其直径,在第二次搜索的时候记录路径,然后就可以取其中点啦!

网上大神用的都是DFS,于是本蒟蒻就义无反顾地用了BFS ( • ̀ω•́ )✧

经本人实测发现的坑点如下:
1.坐标只是给你连边用的,之后跑搜索的时候权值都为1。
2.因为题目上说是逐步占领的,这就意味着对于第i个点,只需考虑前i-1个点到它的距离即可(就是因为这个地方我RE了)。
3.若有两个中点的话先输编号小的那个。

就酱。

贴上代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define MAXN 1000
using namespace std;
struct edge{
    int next;
    int to;
};
int n,m;
int a[MAXN+5][5],num[MAXN+5],h[MAXN+5];
int w[MAXN+5],pre[MAXN+5],b[MAXN+5],v[MAXN+5];
double dis[MAXN+5];
edge ed[2*MAXN+5];
bool f[MAXN+5];
double calc(int x1,int y1,int z1,int x2,int y2,int z2){
    double x=x2-x1;
    double y=y2-y1;
    double z=z2-z1;
    return sqrt(x*x+y*y+z*z);
}
void read(int x,int y){
    ed[++m].next=h[x];
    ed[m].to=y;
    h[x]=m;
}
void bfs1(){
    memset(w,0,sizeof(w));
    memset(f,false,sizeof(f));
    b[1]=1;
    int l=0,r=1;
    while (l<r){
        int x=b[++l];
        f[x]=true;
        for (int i=h[x];i;i=ed[i].next)
            if (!f[ed[i].to]){
                w[ed[i].to]=w[x]+1;
                b[++r]=ed[i].to;
            }
    }
}
int bfs(int now){
    memset(f,false,sizeof(f));
    memset(v,0,sizeof(v));
    memset(pre,0,sizeof(pre));
    b[1]=now; 
    int l=0,r=1;
    while (l<r){
        int x=b[++l];
        f[x]=true;
        for (int i=h[x];i;i=ed[i].next)
            if (!f[ed[i].to]){
                v[ed[i].to]=v[x]+1;
                b[++r]=ed[i].to;
                pre[ed[i].to]=x; 
            }
    }
    int ans=0,sum=0;
    for (int i=1;i<=n;i++)
        if (sum<v[i]){
            sum=v[i];
            ans=i;
        }
    return ans;
}
int main(){
    while(~scanf("%d",&n)&&n){
        memset(a,0,sizeof(a));
        memset(dis,127,sizeof(dis));
        for (int i=1;i<=n;i++)
            scanf("%d%d%d%d",&a[i][1],&a[i][2],&a[i][3],&a[i][4]);
        for (int i=1;i<=n;i++)
            for (int j=1;j<i;j++)
                if (calc(a[i][2],a[i][3],a[i][4],a[j][2],a[j][3],a[j][4])<dis[i]){
                    dis[i]=calc(a[i][2],a[i][3],a[i][4],a[j][2],a[j][3],a[j][4]);
                    num[i]=j;
                }
        m=0;
        memset(h,0,sizeof(h));
        for (int i=1;i<=n;i++){
            read(i,num[i]);
            read(num[i],i);
        }
        bfs1();
        int x,sum=0;
        for (int i=1;i<=n;i++)
            if (w[i]>sum){
                sum=w[i];
                x=i;
            }
        int y=bfs(x);
        if (v[y]%2==0){
            int t=1,now=y;
            while(t!=v[y]/2+1){
                t++;
                now=pre[now];
            }
            printf("%d\n",now);
        }
        else{
            int t=1,now=y;
            while (t!=v[y]/2+1){
                t++;
                now=pre[now];
            }
            int k=a[now][1];
            now=a[pre[now]][1];
            if (k>now) swap(k,now);
            printf("%d %d\n",k,now);
        }
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值