HDU 5992 Finding Hotels(KD树)题解
题意:n家旅店,每个旅店都有坐标x,y,每晚价钱z,m个客人,坐标x,y,钱c,问你每个客人最近且能住进去(非花最少钱)的旅店,一样近的选排名靠前的。
思路:KD树模板题
代码:
#include<set>
#include<map>
#include<stack>
#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
typedef long long ll;
const int maxn = + ;
const int seed = ;
const ll MOD = 1e9 + ;
const int INF = 0x3f3f3f3f;
using namespace std; #define lson rt << 1
#define rson rt << 1 | 1
#define Pair pair<ll, Node> int k, idx; //维数k struct Node
{
int feature[]; //定义属性数组
int id;
bool operator < (const Node &u) const
{
return feature[idx] < u.feature[idx];
}
}_data[maxn], p; //_data[]数组代表输入的数据
Node data[ * maxn]; //data[]数组代表K-D树的所有节点数据
int flag[ * maxn]; //用于标记某个节点是否存在,1表示存在,-1表示不存在 priority_queue<Pair> Q; //队列Q用于存放离p最近的m个数据
ll Sqrt(ll a, ll b){ //欧几里得距离平方
return (a - b) * 1LL * (a - b);
} //建树步骤,参数dept代表树的深度
void Build(int l, int r, int rt, int dept)
{
if(l > r) return;
flag[rt] = ; //表示编号为rt的节点存在
flag[lson] = flag[rson] = -; //当前节点的孩子暂时标记不存在
idx = dept % k; //按照编号为idx的属性进行划分
int mid = (l + r) >> ;
nth_element(_data + l, _data + mid, _data + r + ); //nth_element()为STL中的函数 algorithm
data[rt] = _data[mid];
Build(l, mid - , lson, dept + ); //递归左子树
Build(mid + , r, rson, dept + ); //递归右子树
} //查询函数,寻找离p最近的m个特征属性
void Query(Node p, int m, int rt, int dept)
{
if(flag[rt] == -) return; //不存在的节点不遍历
Pair cur(, data[rt]); //获取当前节点的数据和到p的距离
for(int i = ; i < k; i++) //欧几里得距离的平方
cur.first += Sqrt((ll)data[rt].feature[i], (ll)p.feature[i]);
int dim = dept % k; //跟建树一样,这样能保证相同节点的dim值不变
bool fg = ; //用于标记是否需要遍历右子树
int x = lson;
int y = rson;
if(p.feature[dim] >= data[rt].feature[dim]) //数据p的第dim个特征值大于等于当前的数据,则需要进入右子树
swap(x, y);
if(~flag[x]) Query(p, m, x, dept + ); //如果节点x存在,则进入子树继续遍历 //以下是回溯过程,维护一个优先队列
if(Q.size() < m) //如果队列没有满,则继续放入
{
if(cur.second.feature[] <= p.feature[]) Q.push(cur);
fg = ;
}
else
{
if(cur.first < Q.top().first && cur.second.feature[] <= p.feature[]) //如果找到更小的距离,则用于替换队列Q中最大的距离的数据
{
Q.pop();
Q.push(cur);
}
else if(cur.first == Q.top().first && cur.second.id < Q.top().second.id && cur.second.feature[] <= p.feature[]){
Q.pop();
Q.push(cur);
}
if(Sqrt((ll)p.feature[dim], (ll)data[rt].feature[dim]) < Q.top().first)
{
fg = ;
}
}
if(~flag[y] && fg)
Query(p, m, y, dept + );
}
int main(){
int T, n, m;
k = ;
scanf("%d", &T);
while(T--){
scanf("%d%d", &n, &m);
for(int i = ; i < n; i++){
for(int j = ; j < ; j++)
scanf("%d", &_data[i].feature[j]);
_data[i].id = i;
}
Build(, n - , , );
while(m--){
while(!Q.empty()) Q.pop();
for(int i = ; i < ; i++)
scanf("%d", &p.feature[i]);
Query(p, , , );
p = Q.top().second;
printf("%d %d %d\n", p.feature[], p.feature[], p.feature[]);
}
}
return ;
}
模板:
#define lson rt << 1
#define rson rt << 1 | 1
#define Pair pair<ll, Node> int k, idx; //维数k struct Node
{
int feature[]; //定义属性数组
int id;
bool operator < (const Node &u) const
{
return feature[idx] < u.feature[idx];
}
}_data[maxn], p; //_data[]数组代表输入的数据
Node data[ * maxn]; //data[]数组代表K-D树的所有节点数据
int flag[ * maxn]; //用于标记某个节点是否存在,1表示存在,-1表示不存在 priority_queue<Pair> Q; //队列Q用于存放离p最近的m个数据
ll Sqrt(ll a, ll b){ //欧几里得距离平方
return (a - b) * 1LL * (a - b);
} //建树步骤,参数dept代表树的深度
void Build(int l, int r, int rt, int dept)
{
if(l > r) return;
flag[rt] = ; //表示编号为rt的节点存在
flag[lson] = flag[rson] = -; //当前节点的孩子暂时标记不存在
idx = dept % k; //按照编号为idx的属性进行划分
int mid = (l + r) >> ;
nth_element(_data + l, _data + mid, _data + r + ); //nth_element()为STL中的函数 algorithm
data[rt] = _data[mid];
Build(l, mid - , lson, dept + ); //递归左子树
Build(mid + , r, rson, dept + ); //递归右子树
} //查询函数,寻找离p最近的m个特征属性
void Query(Node p, int m, int rt, int dept)
{
if(flag[rt] == -) return; //不存在的节点不遍历
Pair cur(, data[rt]); //获取当前节点的数据和到p的距离
for(int i = ; i < k; i++) //欧几里得距离的平方
cur.first += Sqrt((ll)data[rt].feature[i], (ll)p.feature[i]);
int dim = dept % k; //跟建树一样,这样能保证相同节点的dim值不变
bool fg = ; //用于标记是否需要遍历右子树
int x = lson;
int y = rson;
if(p.feature[dim] >= data[rt].feature[dim]) //数据p的第dim个特征值大于等于当前的数据,则需要进入右子树
swap(x, y);
if(~flag[x]) Query(p, m, x, dept + ); //如果节点x存在,则进入子树继续遍历 if(Q.size() < m) //如果队列没有满,则继续放入
{ //注意,这里必须让fg=1,以后改时注意
Q.push(cur);
fg = ;
}
else
{
if(cur.first < Q.top().first) //如果找到更小的距离,则用于替换队列Q中最大的距离的数据
{
Q.pop();
Q.push(cur);
}
if(Sqrt((ll)p.feature[dim], (ll)data[rt].feature[dim]) < Q.top().first)
{
fg = ;
}
}
if(~flag[y] && fg)
Query(p, m, y, dept + );
}
HDU 5992 Finding Hotels(KD树)题解的更多相关文章
- HDU 5809 Ants(KD树+并查集)
[题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=5809 [题目大意] 给出一些蚂蚁和他们的巢穴,一开始他们会在自己的巢穴(以二维坐标形式给出),之后 ...
- K-D树问题 HDU 4347
K-D树可以看看这个博客写的真心不错!这里存个版 http://blog.csdn.net/zhjchengfeng5/article/details/7855241 HDU 4349 #includ ...
- 2016 ICPC青岛站---k题 Finding Hotels(K-D树)
题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=5992 Problem Description There are N hotels all over ...
- 【HDU5992】Finding Hotels 【KD树】
题意 给出n个酒店的坐标和价格,然后m个查询,每个查询给出一个人的坐标和能承受的最大价格,然后找出在他价格承受范围以内,距离他最近的宾馆,如果有多个,那么输出第一个 分析 kd树的模板题 #inclu ...
- bzoj 3053 HDU 4347 : The Closest M Points kd树
bzoj 3053 HDU 4347 : The Closest M Points kd树 题目大意:求k维空间内某点的前k近的点. 就是一般的kd树,根据实测发现,kd树的两种建树方式,即按照方差 ...
- HDU 6022---MG loves set(K-D树)
题目链接 Problem Description MG is an intelligent boy. One day he was challenged by the famous master ca ...
- hdu 4347 The Closest M Points (kd树)
版权声明:本文为博主原创文章,未经博主允许不得转载. hdu 4347 题意: 求k维空间中离所给点最近的m个点,并按顺序输出 . 解法: kd树模板题 . 不懂kd树的可以先看看这个 . 不多说, ...
- 数据结构(KD树):HDU 4347 The Closest M Points
The Closest M Points Time Limit: 16000/8000 MS (Java/Others) Memory Limit: 98304/98304 K (Java/Ot ...
- hdu 2966 In case of failure k-d树
题目链接 给n个点, 求出每个点到离它最近的点的距离. 直接建k-d树然后查询就可以 感觉十分神奇... 明白了算法原理但是感觉代码还不是很懂... #include <bits/stdc++ ...
随机推荐
- 2018/03/19 每日一个Linux命令 之 touch
touch 英文翻译为 触碰 很形象 touch [文件] 就像我就碰你一下,什么都不干..... 如果没有这个文件则我就新建这个文件 会修改这个文件的最后修改时间 没有的话则会产生一个0字节大小的空 ...
- 洛谷P2414 阿狸的打字机 [NOI2011] AC自动机+树状数组/线段树
正解:AC自动机+树状数组/线段树 解题报告: 传送门! 这道题,首先想到暴力思路还是不难的,首先看到y有那么多个,菜鸡如我还不怎么会可持久化之类的,那就直接排个序什么的然后按顺序做就好,这样听说有7 ...
- [python-opencv]超大图像二值化方法
*分块 *全局阈值 VS 局部阈值 import cv2 as cv import numpy as np def big_image_binary(image): print(image.shape ...
- flask中的信号量
一.在flask中自定义信号 from flask import Flask, current_app, flash, render_template from flask.signals impor ...
- JavaScript中通过arguments对象实现对象的重载
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- visio 的使用方法
1:往visio中添加商务图形和形状的方法.例如饼状图. 文件>形状>商务>图表和图形>绘制图表形状 2:visio 画半弧形,用铅笔 3: visio 画的图形,如果想要和v ...
- [vue]组件最佳实战
[vue]全局组件和局部组件(嵌套+props引用父组件数据) [vue]组件篇 [vue]组件的创建(componet)和销毁(keep-alive缓存)和父子dom同步nextTick [vue] ...
- hdu1864最大报销额(01背包)
http://acm.sdut.edu.cn:8080/vjudge/contest/view.action?cid=187#problem/G 该题要注意的就是每张单子A种类的总和不能大与600,同 ...
- javascript本地,宿主,内置对象
一.本地对象:官方定义的对象独立于宿主环境的 ECMAScript 实现提供的对象,包括操作系统和浏览器.本地对象就是 ECMA-262 定义的类(引用类型).“本地对象”包含内容: Object ...
- Android常用权限permission列表摘录
一个Android应用程序需要权限才能调用某些android系统的功能:一个android应用也可能被其他应用调用,因此也需要声明调用自身所需要的权限.除了平时常用的权限记得比较熟悉,还有很多的权限一 ...