HDU 5102 The K-th Distance(队列模拟,数组模拟邻接表)

来源:互联网 发布:tbq淘宝权微博 编辑:程序博客网 时间:2024/09/21 08:59

题意:T组数据,每组数据第一行两个数n,k。n表示点的个数,接下来n-1行每行两个数,表示两个点的连线,形成简单无环图。在这个图中找到任意两个点的距离有n*(n-1)/2个距离从小到大排序。取前k项的和。

官方题解:

把所有边(u,v) 以及(v,u)放入一个队列,队列每弹出一个元素(u,v),对于所有与u相邻的点w,如果w!=v,就把(w,u)入队。这样就能一个一个生成前K小的距离。 注意到每条边实际上会入队两次,只要把K翻倍且把ans除2即可,时间复杂度为O(n+K);

这里只是实现一下而已。

题目链接HDU 5102

AC代码:

#include <iostream>#include <stdio.h>#include <cmath>#include <cstring>#include <queue>using namespace std;typedef long long ll;typedef long long LL;const ll maxn=100050;int head[maxn+7],tot=0; ///head是邻接表中的头结点的定义,邻接表中节点的个数ll ans,k,n;struct node///存储到队列中表示从u点到v点路径的长度为d{    int u,v,d;    node(int _u,int _v,int _d):u(_u),v(_v),d(_d){}    node(){}};struct endge///邻接表中的边定义{    int v,next;}G[maxn<<2+7];///因为建图时要双向加边所以要开两倍void addeduge(int u,int v)///加边操作,u为头节点{    G[tot].v=v;    G[tot].next=head[u];    head[u]=tot++;}queue <node> q;void bfs(){    int cnt=0;///表示已经找的的最小项的个数    while(!q.empty())    {        if(cnt>=k)  break;        node tmp=q.front();        q.pop();        int u=tmp.u;        int v=tmp.v;        int d=tmp.d;        if(cnt>=k)  break;        for(int i=head[u];i!=-1;i=G[i].next)        {            int vv=G[i].v;            if(vv!=v)            {                ans+=d+1;                cnt++;                q.push(node(vv,u,d+1));///查找完当前边之后路径长度加1            }            if(cnt>=k)  break;        }        if(cnt>=k)  break;    }}int main(){    int T;    scanf("%d",&T);    while(T--)    {        while(!q.empty())///清空队列            q.pop();        memset(head,-1,sizeof(head));        tot=0;        ans=0;        scanf("%I64d%I64d",&n,&k);        int u,v;        for(int i=1;i<=n;i++)   q.push(node(i,i,0));///将每个点的本身加入队列        for(int i=0;i<n-1;i++)        {            scanf("%d%d",&u,&v);            addeduge(u,v);            addeduge(v,u);///双向加边        }        k*=2;///每个边的路径加了两次,所以将查找的边个数乘2.        bfs();        printf("%I64d\n",ans/2);///答案也应该除2    }    return 0;}


0 0