2016 ICPC青岛站---k题 Finding Hotels(K-D树)

题目链接

http://acm.hdu.edu.cn/showproblem.php?pid=5992

 

Problem Description
There are N hotels all over the world. Each hotel has a location and a price. M guests want to find a hotel with an acceptable price and a minimum distance from their locations. The distances are measured in Euclidean metric.
 
Input
The first line is the number of test cases. For each test case, the first line contains two integers N (N ≤ 200000) and M (M ≤ 20000). Each of the following N lines describes a hotel with 3 integers x (1 ≤ x ≤ N), y (1 ≤ y ≤ N) and c (1 ≤ c ≤ N), in which x and y are the coordinates of the hotel, c is its price. It is guaranteed that each of the N hotels has distinct x, distinct y, and distinct c. Then each of the following M lines describes the query of a guest with 3 integers x (1 ≤ x ≤ N), y (1 ≤ y ≤ N) and c (1 ≤ c ≤ N), in which x and y are the coordinates of the guest, c is the maximum acceptable price of the guest.
 
Output
For each guests query, output the hotel that the price is acceptable and is nearest to the guests location. If there are multiple hotels with acceptable prices and minimum distances, output the first one.
 
Sample Input
2
3 3
1 1 1
3 2 3
2 3 2
2 2 1
2 2 2
2 2 3
5 5
1 4 4
2 1 2
4 5 3
5 2 1
3 3 5
3 3 1
3 3 2
3 3 3
3 3 4
3 3 5
 
Sample Output
1 1 1
2 3 2
3 2 3
 
5 2 1
2 1 2
2 1 2
1 4 4
3 3 5
 
Source
 
 
题意:有n个旅店(x,y,c),(x,y,c)表示旅店的平面坐标和住宿价格,现在有m个游客(x,y,c)想住宿,(x,y,c)表示游客的平面坐标和最高接受的价格,现在要求输出每一位游客选择的旅店(价格在小于游客接受的最高价格下的最近的旅店,如果有多个旅店符合要求,输出输入时排在前面的旅店);
 
思路:K-D树,我在参加青岛现场赛时根本不知道这个算法,所以没做出来,最后铜牌了,有点可惜。这道题不难,是一道K-D树的模板题(如果不知道K-D树,想了解的话,看苟神的博客)。K-D树其实说到底是一棵二叉搜索树,但普通的二叉搜索树的节点是一维的,可以比较大小的向下搜索到叶子节点找到解,但K-D树的每个节点是多维的,在每个节点处有多维,这多维分量共同对结果产生影响,那么可以采用计算方差或者每一个分量轮流着来进行划分(我看网上大部分人都觉得使用每一个分量轮流来划分方法比较好,我以这种方法为例叙说),这样就不能绝对保证另一边的子树一定不包含解,但包含解的可能性要小于这边的子树,所以求解时优先搜索这边的子树,在回溯时判断另一边的子树是否需要搜索。从整体上看呢,感觉K-D树是一种暴力搜索+剪枝。
唉,自己还是太弱,加油!
 
代码如下:(另外这题,我写完用C++提交超时了,看了一下本题排名,发现所有过的代码都是G++提交的,我试着G++提交,过了。我不太明白这两种方式有什么不同,可有大神能说一下^_^)
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <queue>
#include <set>
#include <bitset>
using namespace std;
#define Sqrt2(x) (x)*(x)
typedef long long LL;
int N,M,idx;

struct Node
{
    int f[3];
    int id;
    bool operator<(const Node& s)const
    {
        return f[idx]<s.f[idx];
    }
}data[200005],tr[4*200005];
int flag[4*200005];
pair<LL,Node> ans;

void build(int l,int r,int i,int deep)
{
    if(l>r) return;
    flag[i]=1;
    flag[i<<1]=0; flag[i<<1|1]=0;
    idx=deep%2;
    int mid=(l+r)>>1;
    nth_element(data+l,data+mid,data+r+1);
    tr[i]=data[mid];
    build(l,mid-1,i<<1,deep+1);
    build(mid+1,r,i<<1|1,deep+1);
}

void query(Node p,int i,int deep)
{
    if(!flag[i]) return ;
    pair<LL,Node> c;
    c.second=tr[i];
    c.first=(LL)(Sqrt2((LL)p.f[0]-tr[i].f[0])+Sqrt2((LL)p.f[1]-tr[i].f[1]));
    bool fg=0;
    int idm=deep%2;
    int x=i<<1;
    int y=i<<1|1;
    if(p.f[idm]>=tr[i].f[idm]) swap(x,y);
    if(flag[x]) query(p,x,deep+1);
    if(ans.first==-1){
        if(c.second.f[2]<=p.f[2])
           ans.first=c.first,ans.second=c.second;
        fg=1;
    }
    else {
        if(c.second.f[2]<=p.f[2]&&(c.first<ans.first||(c.first==ans.first&&c.second.id<ans.second.id)))
            ans.first=c.first,ans.second=c.second;
        if((LL)(Sqrt2(tr[i].f[idm]-p.f[idm]))<ans.first)
            fg=1;
    }
    if(fg&&flag[y]) query(p,y,deep+1);
}

int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        scanf("%d%d",&N,&M);
        for(int i=1;i<=N;i++)
        {
            for(int j=0;j<3;j++)
             scanf("%d",&data[i].f[j]);
            data[i].id=i;
        }
        build(1,N,1,0);
        while(M--)
        {
            Node p;
            for(int i=0;i<3;i++)
                scanf("%d",&p.f[i]);
            ans.first=-1;
            query(p,1,0);
            printf("%d %d %d\n",ans.second.f[0],ans.second.f[1],ans.second.f[2]);
        }
    }
    return 0;
}
View Code

 

posted @ 2016-11-20 16:09 茶飘香~ 阅读(...) 评论(...) 编辑 收藏