hdu 5102(巧妙的搜索)

The K-th Distance

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


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
 

 

Source
 
题意:求出一棵树里面每两个点之间距离的前K大之和。
题解:

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

这种搜索方式还是第一次看到。。

 

 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include <queue>
using namespace std;
const int N = 100005;
int n,k,ans;

struct node{
    int u,v,w;
    node(){};
    node(int _u,int _v,int _w):u(_u),v(_v),w(_w){};
};
queue<node> q;
struct Edge{
    int v,next;
}edge[2*N];
int head[N];
int tot;
void addedge(int u,int v,int &k){
    edge[k].v = v,edge[k].next = head[u],head[u] = k++;
}
void init(){
    memset(head,-1,sizeof(head));
    tot= 0;
}
void bfs(){
    int cnt = 0;
    while(!q.empty()){
        node temp = q.front();
        q.pop();
        int u = temp.u,v=temp.v,w = temp.w;
        if(cnt>=k) break;
        for(int i=head[u];i!=-1;i=edge[i].next){
            int _v = edge[i].v;
            if(_v!=v){
                ans +=w+1;
                cnt++;
                q.push(node(_v,u,w+1));
            }
            if(cnt>=k) break;
        }
        if(cnt>=k) break;
    }
}
int main(){
    int tcase;
    scanf("%d",&tcase);
    while(tcase--){
        while(!q.empty()) q.pop();
        init();
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++) q.push(node(i,0,0));
        for(int i=1;i<n;i++){
            int u,v;
            scanf("%d%d",&u,&v);
            addedge(u,v,tot);
            addedge(v,u,tot);
        }
        ans = 0;
        k = 2*k;
        bfs();
        printf("%d\n",ans/2);
    }
    return 0;
}

 

 

 

posted @ 2016-07-11 16:48  樱花庄的龙之介大人  阅读(196)  评论(0编辑  收藏  举报