蓝桥杯每日真题之直线

题目来源

2021年蓝桥杯省赛

题目链接:http://acm.mangata.ltd/p/P1485

考点

数学、暴力

视频讲解

https://www.bilibili.com/video/BV1BY411J795

思路

因为选取的点都是整数坐标的,于是我们最多选取 21 × 20 = 420 21\times 20 = 420 21×20=420 个点,那么对于其中每两个点我们都能选来作为一条直线,但是这样的话可能会存在重复选择一条线,于是我们需要去重处理,那么怎么去重呢?我们知道对于一个直线的标准方程为: A x + B y + C = 0 Ax+By+C = 0 Ax+By+C=0 那么也就是说我们只要确定了 A 、 B 、 C A、B、C ABC 即可,不过这里需要注意这里的 A 、 B 、 C A、B、C ABC 是需要最简化的,否则就不能达到我们去重的效果,对于三个元素或者多个元素的结构去重,我们可以选择自己写一个结构体,但是我们也可以直接使用 vector ,然后把每个vector 扔进 set 里面即可,那么我们怎么求得 A 、 B 、 C A、B、C ABC 呢?,大家都知道两点确定直线的方程: ( y − y 1 ) y 1 − y 2 = x − x 1 x 1 − x 2 \frac{(y - y_1)}{y_1-y_2} = \frac{x-x_1}{x_1-x_2} y1y2(yy1)=x1x2xx1 那么我们稍微等式变换一下就能得到: ( y 2 − y 1 ) x + ( x 1 − x 2 ) y + ( x 2 y 1 − x 1 y 2 ) = 0 (y_2 - y_1)x + (x_1-x_2)y + (x_2y_1-x_1y_2) = 0 (y2y1)x+(x1x2)y+(x2y1x1y2)=0

我们和上面一一对应就能得到: A = y 2 − y 1 、 B = x 1 − x 2 、 C = x 2 y 1 − x 1 y 2 A=y_2 - y_1、B=x_1-x_2、C=x_2y_1-x_1y_2 A=y2y1B=x1x2C=x2y1x1y2,那么我们在将三者的公因数都除掉后放入vector中,再丢入set 就完成了一条线的计算,最后我们只需要输出set容器里面的大小即可

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define mod 1000000007
#define endl "\n"
#define PII pair<int,int>
#define INF 0x3f3f3f3f

const double eps = 0.0000001;

int main()
{
    
    
	vector<PII> Point;
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	int n = 20,m = 21;
//	cin>>n>>m;

	for(int x = 0;x < n; ++x)
		for(int y = 0;y < m; ++y)
			Point.push_back({
    
    x,y});

	int l = Point.size();
	set<vector<int>> ans;
	for(int i = 0;i < l; ++i) {
    
    
		for(int j = i + 1;j < l; ++j) {
    
    
			vector<int> t;
			int x1 = Point[i].first,y1 = Point[i].second;
			int x2 = Point[j].first,y2 = Point[j].second;
			int a,b,c;
			a = y2 - y1;
			b = x1 - x2;
			c = x2 * y1 - x1 * y2;
			int d = __gcd(__gcd(a,b),c);
			t.push_back(a/d);
			t.push_back(b/d);
			t.push_back(c/d);
			ans.insert(t);
		}
	}
	cout<<ans.size()<<endl;
	return 0;
}
/*
ans = 40257
*/

猜你喜欢

转载自blog.csdn.net/m0_46201544/article/details/123910901