Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。
题目描述
在平面直角坐标系中,两点可以确定一条直线。如果有多点在一条直线上,那么这些点中任意两点确定的直线是同一条。 给定平面上 个整点 ,即横坐标是 到 (包含 和 ) 之间的整数、纵坐标是 到 (包含 和 ) 之间的整数的点。这些点一共确定了 条不同的直线。 给定平面上 个整点 ,即横坐标是 到 (包含 和 ) 之间的整数、纵坐标是 到 (包含 和 ) 之间的整数的点。请问这些点一共确定了多少条不同的直线。
思路详解——第二次迭代版本
上次我们使用的直线方程是斜截式,由于斜率k是同时含分子分母的数,表达比较繁琐。
本次经过迭代后的代码使用的直线方程是一般式:。 经过计算,设两点确定一条直线,则:
注意,两条完全相同的直线其不一定是相同的,而是有可能具有相同的倍数,如同与是同一条直线。因此对于每两个点,它们算出来的我们需要化成最简,方法就是同时除以它们三个共同的.三个数的计算方式如下: (其实对于任意多的数都可以如此递归求) 同时,如果是负数,把同时乘以。这样,所有计算出来的直线方程都转换为了最简式且非负,判断相等的方式变味了最简单的:同时相等。
struct line{
int a,b,c;//坚持a是正数
};
line getline(int x1,int y1,int x2,int y2){
int a=y2-y1;
int b=x2-x1;
int c=(x2-x1)*y1-(y2-y1)*x1;
int tmp=gcd(abs(a),abs(b),abs(c));
a=a/tmp,b=b/tmp,c=c/tmp;
if(a<0)a=-a,b=-b,c=-c;
return line{a,b,c};
}
最后还有一个小点需要注意那就是这个表达方式不支持k=0和k不存在的情况。解决方法就是y_1=y_2或x_1=x_2时跳过,最后在结果上加41即可。
本次的代码,相比上次的繁琐的表达方式有了很大改进。下面搬出完整代码。
完整代码
#include<bits/stdc++.h>
using namespace std;
#define pb push_back
#define pp pop_back
using ll=long long;
using db =double;
int gcd(int a,int b){
if(a<b)return gcd(b,a);
if(b==0)return a;
return gcd(b,a%b);
}
int gcd(int a,int b,int c){
return gcd(gcd(a,b),c);
}
struct line{
int a,b,c;//坚持a是正数
bool operator==(const line &x)const{
return a==x.a&&b==x.b&&c==x.c;
}
};
line getline(int x1,int y1,int x2,int y2){
int a=y2-y1;
int b=x2-x1;
int c=(x2-x1)*y1-(y2-y1)*x1;
int tmp=gcd(abs(a),abs(b),abs(c));
a=a/tmp,b=b/tmp,c=c/tmp;
if(a<0)a=-a,b=-b,c=-c;
return line{a,b,c};
}
vector<line> lines;
int main(){
cout<<lines.size()<<' ';
for(int x1=0;x1<=19;x1++){
for(int y1=0;y1<=20;y1++){
for(int x2=0;x2<=19;x2++){
for(int y2=0;y2<=20;y2++){
if(y2-y1==0||x2-x1==0)continue;
auto li=getline(x1,y1,x2,y2);
int flag=1;
for(auto li2:lines){
if(li2==li)flag=0;
}
if(flag)lines.pb(li);
}
}
}
}
cout<<lines.size()+20+21;
return 0;
}