hdu 5102 The K-th Distance(特殊的搜索技巧)

博客介绍了如何解决HDU 5102题目中的特殊搜索技巧,即找到树上的第K小距离。错误的方法是枚举所有点并逐点搜索,而正确方法是采用广度优先搜索(BFS),将所有点放入队列中,避免死循环,并对点对计数除以2得到前K小距离。
摘要由CSDN通过智能技术生成

The K-th Distance

Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 751    Accepted Submission(s): 215


Problem Description
Given a tree, which has n node in total. Define the distance between two node u and v is the number of edge on their unique route. So we can have n(n-1)/2 numbers for all the distance, then sort the numbers in ascending order. The task is to output the sum of the first K numbers.
 

Input
There are several cases, first is the number of cases T. (There are most twenty cases).
For each case, the first line contain two integer n and K ( 2n100000,0Kmin(n(n1)/2,106)  ). In following there are n-1 lines. Each line has two integer u , v. indicate that there is an edge between node u and v.
 

Output
For each case output the answer.
 

Sample Input
  
  
2 3 3 1 2 2 3 5 7 1 2 1 3 2 4 2 5
 

Sample Output
  
  
4 10
题意:给一棵树,树上一条边是1,求树上所有点对里面第k小的点对对应的长度

比如1-2-3  前三小分别是1-2(1) 2-3(1) 1-2-3(2)

思路:队友把这种搜索方式称之为洪水式搜索...

就是枚举所有点,然后以当前点为点对里的第一个点在树上搜索下一个点(i,x),也就是已知i搜索x,遍历一次树,找到第k小的

这样做是对的?!  NO!  是错的。 我们要的是从小到大的第k个,那么如果我们一个一个点去枚举无法保证是第k小。(以1为点对的第一个点有可能搜索长度为9,10的,这些不应该在前k小个数里)

所有我们要一次性把所有点都放到一个队列里面,然后用BFS去搜索,这样按照步数我们就能先遍历完长度为1的所有边,然后才会去遍历长度为2的边,注意“”要记录当前点是怎么来的,不能怎么来怎么去,会进入死循环。(比如从1-2,下一次你遍历2又遍历了2-1,那就死循环了)“”

因为点对会进入两次(比如1-2,2-1),所有我们要搜索前2*k个的和,然后最后除以2即可。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
using namespace std;
#define N 100010
struct Edge
{
    int v,next;
} edge[N*4];
struct Node
{
    int u,v,d;
} p[N*20];
int cnt,head[N];
long long ans;
int k;
queue<Node>q;
void init()
{
    cnt=0;
    memset(head,-1,sizeof(head));
    while(!q.empty()) q.pop();
}
void addedge(int u,int v)
{
    edge[cnt].v=v;
    edge[cnt].next=head[u];
    head[u]=cnt++;
}
void bfs()
{
    int cnt=0;
    while(!q.empty())
    {
        Node now=q.front();
        q.pop();
        int u=now.u,v=now.v,d=now.d;
        for(int i=head[u]; i!=-1; i=edge[i].next)
        {
            int vv=edge[i].v;
            if(vv!=v)
            {
                ans+=d;
                cnt++;
                Node next;
                next.u=vv,next.v=u,next.d=d+1;
                q.push(next);
            }
            if(cnt>=k) break;
        }
        if(cnt>=k) break;
    }
}
int main()
{
    int T,s,t;
    int n;
    scanf("%d",&T);
    while(T--)
    {
        init();
        scanf("%d %d",&n,&k);
        Node now;
        for(int i=1; i<=n; i++)
        {
            now.u=i,now.v=i,now.d=1;
            q.push(now);
        }
        for(int i=1; i<n; i++)
        {
            scanf("%d %d",&s,&t);
            addedge(s,t);
            addedge(t,s);
        }
        ans=0;
        k=k*2;
        bfs();
        printf("%lld\n",ans/2);
    }
    return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值