UVA 11768 格点判断

这题做起来非常蛋疼,故在此记录。

求线段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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值