这题做起来非常蛋疼,故在此记录。
求线段AB穿过多少个格点?
根据直线方程可列出关于 x , y 的二元一次方程, 问题转化为求此方程落在AB之间的整数解得个数 ,可就是这个问题非常不好处理。
数据读入容易避免浮点误差
为使方程不出现小数,将坐标乘以10 , 可这样容易 导致最后要求的是整10点的个数? 怎么破。。 又回到了原来的问题。。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long LL ;
const double eps = 1e-8 ;
int sig(double x) {
return (x>eps) - (x<-eps) ;
}
int floor10(int a) {
for(;;a--) if(a%10==0) return a ;
}
int ceil10(int a) {
for(;;a++) if(a%10==0) return a;
}
int readint(){ // 特殊读入方式。
int a ,b;
char buf[20] ;
scanf("%s" , buf) ;
if(buf[0] == '-') {
sscanf(buf+1 , "%d.%d" ,&a , &b) ;
return -(a*10 + b) ;
}
else {
sscanf(buf , "%d.%d" , &a , &b) ;
return a*10 + b ;
}
}
void gcd(LL a , LL b , LL &d , LL &x , LL &y) {
if(b==0) d = a , x = 1 ,y = 0 ;
else gcd(b , a%b , d , y , x), y-=a/b*x ;
}
int solve(LL x1 , LL y1 ,LL x2 ,LL y2) {
LL a = (y2 - y1) * 10 ; // 乘以10 是为了避开 求方程的整10解 , 因为我们只会求整数解啊。。
LL b = (x1 - x2) * 10 ;
LL c = (y2-y1) * x1 - (x2 - x1) * y1 ;
LL g , x , y ;
gcd(a , b , g , x, y) ;
if(c%g != 0) return 0 ;
LL x0 = x * c / g , y0 = y * c / g ;
LL bb = abs( b / g );
LL k1 = (x1/10 - x0) / bb - 5 , k2 = (x2/10 - x0) / bb + 5 ;
while( (x0 + k1*bb)*10 < x1 ) k1 ++ ;
while( (x0 + k2*bb)*10 > x2 ) k2 -- ;
return max(0LL , k2 - k1 + 1) ;
}
int main()
{
//freopen("in.txt" ,"r" ,stdin) ;
int T;
LL x1 , y1 , x2 , y2 ;
scanf("%d" ,&T) ;
while(T--) {
x1 = readint() , y1 = readint() , x2 = readint() , y2 = readint() ;
int ans;
if(x1 == x2) {
if(y1 > y2) swap(y1 , y2) ;
ans = floor10(y2)/10 - ceil10(y1)/10 + 1 ;
if(x1 % 10) ans = 0 ;
}
else if(y1 == y2){
if(x1 > x2) swap(x1 , x2) ;
ans = floor10(x2)/10 - ceil10(x1)/10 + 1 ;
if(y1 % 10) ans = 0 ;
}
else {
if(x1 > x2) swap(x1 , x2) , swap(y1 , y2) ;
ans = solve(x1 , y1 , x2 , y2) ;
}
ans = max(ans , 0 ) ;
printf("%d\n" , ans) ;
}
return 0;
}