自然数与有理数的双射函数(代码实现+思路)

本文介绍了一种将有理数映射到自然数的双射函数实现方法,通过构造8个方向的操作并按特定规律切换方向,最终实现有理数到自然数的一一对应。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一. 程序题(共1题,100分)

  1. (程序题)
    N:自然数, Q:有理数,构造双射函数(双射函数概念请看离散数学)
    在这里插入图片描述输入:多行,每行两个整数a和b,中间有一个空格,表示一个有理数a/b
    输出:对应的多行,每行一个整数,有理数a/b的双射函数对应的自然数,结果<500000
    输入样例:
    -2 1
    -4 1
    -1 2
    输出样例:
    5
    19
    3

解题思路:看到箭头我就想到走迷宫,走迷宫要定义上下左右四个方向,而此题也类似,观察图像我们可以知道箭头的方向是8次一个循环。如图:
在这里插入图片描述
所以我们和图示一样构造8个方向的操作,那么问题的关键来了,我们什么时候换方向呢?仔细观察不难发现,需要改变方向时我们会碰到的坐标分别是x/1 ,x属于整数,以及,1/2 ,-1/2, -2/3 ,2/3…,这些都是很容易找规律的坐标点,我们需要按照图中方向的顺序来依次保存他们,值得注意的是x/1是非常特殊的坐标,我们不需要保存,只需要当y=1时就变向即可,而且变向后向前的步数为1。如此我们根据这个规律就可以找到足够多的x/y的数据,每次获得一个x/y,利用一个set来保存x➗y的值,将set的size()用来记录x/y右上角的唯一编号。有了这个思路我们就能写出代码了。
代码如下:

#include<bits/stdc++.h>
using namespace std;
double x = 0;
double y = 1;
int times  = 0;
int n = 0;
int len = 0;
double xx ;
double yy ;
double x2;
double y2;
set<double> res;//上标 

pair<pair<int,int>,int> res6[755555];//不能用map,map太耗时 

int odd = 2;
const int N =1200;

//记录所有的中转点
pair<int, int> xy[N];
void init(){
    int a1 = 1;
    int a2 = 2;
    int k = 0;
    int i = 0;
    while(k < N/2){
        if(odd%2==0){
            xy[i].first = a1;
            xy[i].second = a2;
            i++;
            xy[i].first = -a1;
            xy[i].second = a2;
            i++;
            a1++;
            a2++;
            k++;
            odd++;
        }else{
            xy[i].first = -a1;
            xy[i].second = a2;
            i++;
            xy[i].first = a1;
            xy[i].second = a2;
            i++;
            a1++;
            a2++;
            k++;
            odd++;
        }
        
    }
    
}

//定义8次循环的操作
void op(int i){
    
    
    if(i==1){
        x++;
        res.insert(x/y);
        res6[len].first = {x,y};
        res6[len].second = res.size()-1;
        len++;
//        cout<<x<<" "<<y;
//        cout<<endl;
    }else if(i==2){
        x2 = xy[n].first;
        y2 = xy[n].second;
//        cout<<"----"<<x1<<" "<<y1;
//        cout<<endl;
        n++;
        while(true){    
            if(y<y2){
                y++;
                res.insert(x/y);
//                cout<<x<<" "<<y;
//                cout<<endl;
            res6[len].first = {x,y};
        	res6[len].second = res.size()-1;
        	len++;
                
            }else{
//                cout<<"break1---";
                break;
            }
        
        }
        
    }else if(i == 3 ){
        x2 = xy[n].first;
        y2 = xy[n].second;
//        cout<<"----"<<x1<<" "<<y1;
//        cout<<endl;
        n++;
        while(true){
            if(x>x2){
                x--;
                res.insert(x/y);
//                cout<<x<<" "<<y;
//                cout<<endl;
                 res6[len].first = {x,y};
        res6[len].second = res.size()-1;
        len++;
            }else{
//                cout<<"break2---";
                break;
            }
        }
    }else if(i==4){
        while(true){
            if(y>1){
                y--;
                res.insert(x/y);
//                cout<<x<<" "<<y;
//                cout<<endl;
            res6[len].first = {x,y};
        res6[len].second = res.size()-1;
        len++;
            }else{
//                cout<<"break3---";
                break;
            }
        }
    }else if(i==5){
        x--;
        res.insert(x/y);
//        cout<<x<<" "<<y;
//        cout<<endl;
        res6[len].first = {x,y};
        res6[len].second = res.size()-1;
        len++;
    }else if(i==6){
        x2 = xy[n].first;
        y2 = xy[n].second;
//        cout<<"----"<<x1<<" "<<y1;
//        cout<<endl;
        n++;
        while(true){
            if(y<y2){
                y++;
                res.insert(x/y);
//                cout<<x<<" "<<y;
//                cout<<endl;
               res6[len].first = {x,y};
        res6[len].second = res.size()-1;
        len++;
            }else{
//                cout<<"break4---";
                break;
            }
        }
    }else if(i == 7){
        x2 = xy[n].first;
        y2 = xy[n].second;
//        cout<<"----"<<x1<<" "<<y1;
//        cout<<endl;
        n++;
        while(true){
            if(x<x2){
                x++;
                res.insert(x/y);
//                cout<<x<<" "<<y;
//                cout<<endl;
                res6[len].first = {x,y};
        res6[len].second = res.size()-1;
        len++;
            }else{
//                cout<<"break5---";
                break;
            }
        }
    }else if(i==8){
        while(true){
            if(y>1){
                y--;
                res.insert(x/y);
//                cout<<x<<" "<<y;
//                cout<<endl;
                res6[len].first = {x,y};
        res6[len].second = res.size()-1;
        len++;
            }else{
//                cout<<"break6---";
                break;
            }
        }
    }
    
    
    
}


int main(){
    init();
    int i ;
    
    //循环获得足够多的x/y数据 
    while(true){
            times++;
            i=1;

            for(;i<=8;i++){
                	op(i);

            }
            if(times>299) break;
        }
        
        
        
        //输出结果 
        while(~scanf("%lf %lf",&xx,&yy)){
            for(int w = 0 ; w < len ; w++){
            	if(res6[w].first.first == xx &&res6[w].first.second == yy ){
            		printf("%d\n",res6[w].second);
            		break;
					}
				}
                

        }
    
    return 0;
}


还有就是别直接黏贴复制,学习通会判0分的。
点点赞吧!

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值