UVA 11768 - Lattice Point or Not

本文详细介绍了扩展欧几里得算法,并通过一个具体的题目示例解释了如何利用该算法来解决寻找线性方程整数解的问题。文中不仅提供了算法的实现代码,还讨论了如何基于该算法确定线性方程所有整数解的方法。

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

首先本题需要用到扩展欧几里得算法……


关于exgcd算法的一点简略证明:



那么,对于函数exgcd(a,b)=(d,x,y),其中d满足d=gcd(a,b); (x,y)满足ax+by=d;

则exgcd(b,a mod b)=(d,x',y'),而此时,使用 x = y' ;  y = x' - floor(a/b) * y' = x' - floor(a/b) * x 就能得到exgcd(a,b)的值。

故我们可以有扩展欧几里得算法如下:

void exgcd(int a,int b,int &d,int &x,int &y){  
	if(!b){d=a;x=1;y=0;}
	else {exgcd(b,a%b,d,y,x);y-=(a/b)*x;}
}
此处的边界条件是exgcd(a,0)=(a,1,0)


那么此时,若c mod gcd(a,b) = 0,就容易求得一个整点(x,y),那么如何得到所有的点?



然后是题目的代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
typedef long long ll;
using namespace std;
void exgcd(ll a,ll b,ll &d,ll &x,ll &y){  
	if(!b){d=a;x=1;y=0;}  
	else {exgcd(b,a%b,d,y,x);y-=(a/b)*x;}
}
int main() {
	double X1,Y1,X2,Y2;
	int t;
	scanf("%d",&t);
	while(t--){
		scanf("%lf%lf%lf%lf",&X1,&Y1,&X2,&Y2);//获得初始坐标(x1,y1),(x2,y2)
		ll x1=X1*10,x2=X2*10,y1=Y1*10,y2=Y2*10;//将坐标都换成整型
		if(x1==x2)//如果这条线是一条竖直的线
		{
			if(x1%10!=0){//如果此时的直线l:x=c,c不是整数,那么这条线上显然没有整点
				printf("0\n");
				continue;
			}
			y2=floor(max(Y1,Y2));
			y1=ceil(min(Y1,Y2));
			printf("%lld\n",y2-y1+1);
			continue;
		}
		if(y1==y2)//如果这条线是一条水平的线
		{
			if(y1%10!=0){//如果此时的直线l:y=c,c不是整数,那么这条线上显然也没有整点
				printf("0\n");
				continue;
			}
			x2=floor(max(X1,X2));
			x1=ceil(min(X1,X2));
			printf("%lld\n",x2-x1+1);
			continue;
		}
		ll a=(y2-y1)*10,b=(x1-x2)*10,c=x1*y2-x2*y1;//计算出l:ax+by=c
		ll x,y,d;
		if(X2<X1) swap(X2,X1);//确保x2>x1
		x1=ceil(X1),x2=floor(X2);
		if(x1>x2){//如果一条线的斜率过大,使得x1,x2有m<x1<x2<m+1 (m为整数),那么显然这个范围内没有整点
			printf("0\n");
			continue;
		}
		ll k=0;
		exgcd(a,b,d,x,y);//得到满足ax+by=gcd(a,b)的(x0,y0)
		if (c%d==0)//如果c是gcd(a,b)的整数倍,即c = k * gcd(a,b),那么显然点( k * x0 , k * y0 )是ax+by=c上的一个整点
		{
			a/=d,b/=d;
			x*=c/d,y*=c/d;
			if(b<0) b=-b;
			x=x-(x-x1)/b*b;
			while(x<x1) x+=b;
			while(x+k*b<=x2) k++;
			printf("%lld\n",k);
		}
		else printf("0\n");
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值