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

Posted 茶飘香~

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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

 

以上是关于2016 ICPC青岛站---k题 Finding Hotels(K-D树)的主要内容,如果未能解决你的问题,请参考以下文章

2016ICPC青岛

倍增/线段树维护树的直径 hdu5993/2016icpc青岛L

2016ACM/ICPC亚洲区青岛站 Coding Contest 费用流

Finding the Radius for an Inserted Circle (2017 ACM-ICPC 亚洲区(南宁赛区)网络赛)

2016 ACM/ICPC亚洲区青岛站现场赛(部分题解)

2018acm-icpc青岛站后记