• 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
    ",ans.second.f[0],ans.second.f[1],ans.second.f[2]);
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    VirtualBox下Ubuntu更改分辨率方法
    Asp.Net防止刷新重复提交数据小记
    耻辱名单新成员,腾讯QQ影音违反开源协议遭谴责
    赛门铁克BERS 2010新增Linux备份还原
    开源邮件服务解决方案 iRedMail0.6.0beta1 发布,支持 FreeBSD
    防止ASP.NET按钮多次提交代码
    与省局网站备案管理系统接口规范试行版文件下载地址
    2010预测:开源ERP难有大作为
    ASP.NET对IIS中的虚拟目录进行操作
    C#三种模拟自动登录和提交POST信息的实现方法
  • 原文地址:https://www.cnblogs.com/chen9510/p/6082807.html
Copyright © 2020-2023  润新知