牛客多校第十场 E Hilbert Sort 递归,排序

题意:

给你一个方阵,再在方阵上给定一些点,按照希尔伯特曲线经过的先后顺序为这些点排序

题解:

定义好比较函数后直接调用排序算法即可。

希尔伯特曲线本来就是用于二维到一维的映射的,因此我们可以考虑对于每一个点预处理出它是希尔伯特曲线上第几个经过的,然后排序。

可以看出,假设在方阵的中心设立一个原点,那么希尔伯特曲线依次经过原点的左上,左下,右下,右上,而这四个象限希尔伯特函数的轨迹是互相对称的,对于不同的象限,首先算出它前面经过的象限的总点数,然后将两个点的相对坐标做不同的对称变换后,递归到小一号的希尔伯特曲线中继续。

#include<iostream>
#include<algorithm>
#include<cassert>
#define LL long long  
using namespace std;
inline int pos(const int &x,const int &y){
    if(x==0 && y==0)return 0;
    if(x==1 && y==0)return 1;
    if(x==1 && y==1)return 2;
    if(x==0 && y==1)return 3;
}
struct Hbt{
    LL x,y;
    int size;
    LL rank;
    LL calc_rank(){
        rank=0;
        LL xx=x,yy=y;
        LL w=1<<(size-1);
        while(w){
            int _pos=pos((int)xx/w,(int)yy/w);
            rank+=w*w*_pos;
            if(_pos==1 || _pos==2){
                //保持原状 
                xx%=w;
                yy%=w;
            }else if(_pos==0){
                //左下右上互换 
                xx%=w;
                yy%=w;
                swap(xx,yy);
            }else if(_pos==3){
                //左上右下互换 
                xx=w-1-xx%w;
                yy=w-1-yy%w;
                swap(xx,yy);
            }
            w>>=1;
        }
        rank+=pos((int)xx,(int)yy);
        return rank;
    }
    friend bool operator <(const Hbt &a,const Hbt &b){
        return a.rank<b.rank;
    }
    Hbt(){}
    Hbt(LL a,LL b,int c){
        x=a;y=b;size=c;
    } 
}p[1000006];
int main(){
    //为计算方便坐标减一存储 
    int n,k;
    scanf("%d %d",&n,&k);
    for(int i=1;i<=n;i++){
        scanf("%lld %lld",&p[i].x,&p[i].y);
        --p[i].x;--p[i].y;
        p[i].size=k;
        p[i].calc_rank();
    }
    sort(p+1,p+1+n);
    for(int i=1;i<=n;i++){
        printf("%lld %lld\n",p[i].x+1,p[i].y+1);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/isakovsky/p/11372312.html