编程题-线段上格点的个数-最大公约数

线段上格点的个数

给定平面上的两个格点P1(x1,y1)和P2(x2,y2),线段上P1P2上,除P1和P2以外一共有多少格点

虽然可以用穷举法,遍历min(x1,x2)≤x≤max(x1,x2)且min(y1,y2)≤y≤max(y1,y2)的格点可以得到正确答案,但是复杂度确实O(|x1?x2|×|y1?y2|),其实这个题的答案是|x1?x2|和|y1?y2|的最大公约数减去1。(注意,|x1?x2|=0且|y1?y2|=0时,答案为0)

原因,首先看一下|x1?x2|和|y1?y2|的最大公约数代表的是啥? 其实可以看成 在横向和竖向的最大的公共等分数, 比如 6 的等分点可以是 1:1:1:1:1:1分成6份 ,也可以是 2:2:2分成3份,或者是 6,只有1份。(其实对应的是 6能被6,3,1整除) 那么 6和9的最大公共等分数是3,即6分为 2:2:2 , 9分为3:3:3. 那么边长为6和9的矩形,按照这样分会是什么情况呢?

通过上图可以看出,大矩形的对角线正好经过 (2,3),(4,6),(6,9) 除开(6,9),就是本体所要求的点。这就是为什么这个题的答案是|x1?x2|和|y1?y2|的最大公约数减去1。

那这个题可以转换为求最大公约数的问题,最大公约数一般使用辗转相除法

辗转想法的原理:

如果有两个自然数a和b(a>b), 可以写成a=k×b+c

情况1:如果c=0,那么gcd(a,b)=b

情况2:如果c≠0, 那么gcd(a,b)=gcd(b,c)

下面提供了3个求最大公约数的方法(顺便一提,a和b的最大公倍数为a×bgcd(a,b)

#include <iostream>
#include <cmath>
using namespace std;
int gcd1(int,int);
int gcd2(int,int);
int gcd3(int,int);
int main(void)
{
    int x1,x2,y1,y2;
    cout<<"input x1,y1,x2,y2"<<endl;
    cin>>x1>>y1>>x2>>y2;
    int abs_x=abs(x1-x2);
    int abs_y=abs(y1-y2);
    int g=gcd3(abs_x,abs_y);
    cout<<g-1<<endl;
    int x_step=(x2-x1)/g;
    int y_step=(y2-y1)/g;
    for(int i=1;i<g;i++)
    {
        cout<<"("<<x1+i*x_step<<","<<y1+i*y_step<<")"<<endl;
    }

}

//非递归的方法
int gcd1(int a,int b)
{

    int c;
    do
    {
        c=a%b;
        a=b;
        b=c;
    }while(c!=0);
    return a;
} 

//递归的方法
int gcd2(int a,int b)
{

    if(b == 0){
        return a;
    }else{
        return gcd2(b,a%b);
    }
}
//辗转相减法
int gcd3(int a,int b)
{
    int c=a-b;
    if(c<0){
        return gcd3(b,a);
    }
    while((a-b)!=0)
    {
        a=a-b;
        if(a<b){
            int tmp=a;
            a=b;
            b=tmp;
        }
    }
    return a;
}
时间: 2024-10-07 22:22:33

编程题-线段上格点的个数-最大公约数的相关文章

python课程单元三编程题讲解(上)

目录 1.快乐的数字 2.凯撒密码I 3.凯撒密码II 4.括号配对检测 A @ ? ??下面向大家介绍一下我在学习python课程的一些题目的解法,如果大家有什么更好的解法请私信我.这里只显示题目与代码. 1.快乐的数字 ???描述:编写一个算法来确定一个数字是否"快乐". 快乐的数字按照如下方式确定:从一个正整数开始,用其每位数的平方之和取代该数,并重复这个过程,直到最后数字要么收敛等于1且一直等于1,要么将无休止地循环下去且最终不会收敛等于1.能够最终收敛等于1的数就是快乐的数字

POJ C程序设计进阶 编程题#4:寻找平面上的极大点

编程题#4:寻找平面上的极大点 来源: POJ (Coursera声明:在POJ上完成的习题将不会计入Coursera的最后成绩.) 注意: 总时间限制: 1000ms 内存限制: 65536kB 描述 在一个平面上,如果有两个点(x,y),(a,b),如果说(x,y)支配了(a,b),这是指x>=a,y>=b; 用图形来看就是(a,b)坐落在以(x,y)为右上角的一个无限的区域内. 给定n个点的集合,一定存在若干个点,它们不会被集合中的任何一点所支配,这些点叫做极大值点. 编程找出所有的极大

编程题:功能:将5个学生记录输入文件d:\stu1.txt中,并且显示在屏幕上。

编程题:文件读写fprintf().fscanf()使用,功能:将5个学生记录输入文件d:\stu1.txt中,并且显示在屏幕上. #include<stdio.h> void main() { FILE *fp;long num;int n,score;char name[20]; int N=5; fp=fopen("d:\\s tu1.txt","w"); for(n=1;n<=N;n++) { scanf("%s%10ld%d&q

编程题:返回指针值的函数,求两个数中较大的数。

#include<stdio.h> int *max(int *x,int *y) { int *q; if(*x>*y)  q=x; else  q=y; return q; } void main() { int a,b,*p; scanf("%d,%d",&a,&b); p=max(&a,&b); printf("%d,%d,max is %d\n",a,b,*p); } 编程题:返回指针值的函数,求两个数中较

编程题:已知一个一维数组a[10]中有10个数,求出第m个数到第n个数的和。其中m、n由键盘输入。

#include<stdio.h> int sum(int *q,int n) { int i,s=0; for(i=0;i<n;i++,q++) s+=*q; return s; } void main() { int n,m,a[10]={1,2,3,4,5,6,7,8,9,10}; int *p; printf("Please input m and n(m<n<10):\n"); scanf("%d,%d",&m,&am

编程题:用一组数组做函数参数来实现,输入两个数,输出其中最大数

#include<stdio.h> float max(float x,float y) { float z; if(x>y)z=x; else z=y; return z; } void main() { float a[2],c; scanf("%f,%f",&a[0],&a[1]); c=max(a[0],a[1]); printf("%f,%f,the max is %f\n",a[0],a[1],c); } 编程题:用一组

编程题:用函数调用实现,求两个数中的最小数。

#include<stdio.h> void main() { float min(float x,float y);  /*函数定义在调用的函数之后,要先声明*/ float a=3,b=4.1; printf("%.1f\n",min(a,b)); printf("%.1f\n",min(5,a*b)); printf("%.1f\n",min(b-1,min(a,b))); } float min(float x,float y

编程题:统计1~20之间不能被3整除的数的个数并输出这些数

以下程序是用break和continue语句来实现的. #include<stdio.h> void main() { int n,s; for(n=1,s=0;n<=20;n=n+1) { if(n%3==0) continue; printf("%d\t",n); s=s+1; } printf("\ntotal:%d\n",s); } 算法分析与流程图: 运行结果: 编程题:统计1~20之间不能被3整除的数的个数并输出这些数,布布扣,bubu

编程题:输入a、b两个数,输出其中最大值。

#include<stdio.h> float max(float x,float y) { float z; if(x>y) z=x; else z=y; return z;} main() { float a,b,c; scanf("%f,%f",&a,&b); c=max(a,b); printf("%f,%f,the max is %f\n",a,b,c); } 输入:23,56 输出:23.000000,56.000000