本题的关键思路:
去重,当k,b这个数对唯一时,直线的数目ans才能++,所以要么用map保证唯一解的个数,要么用set去重
求k ,b的公式 k=y1-y2/x1-x2; b=(x2*y1-x1*y2)/x1-x2;
平行于y轴的直线,k等于正无穷,所以要在答案上另外加上20,因为有20 列
题目:
在平面直角坐标系中,两点可以确定一条直线。如果有多点在一条直线上, 那么这些点中任意两点确定的直线是同一条。
给定平面上 2 × 3 个整点(x,y)∣0≤x<2,0≤y<3,x∈Z,y∈Z {(x, y)|0 ≤ x < 2, 0 ≤ y < 3, x ∈ Z, y ∈ Z},即横坐标 是 0到 1 (包含 0 和 1) 之间的整数、纵坐标是 0 到 2 (包含 0 和 2) 之间的整数 的点。这些点一共确定了 11 条不同的直线。
给定平面上 20×21 个整点 (x,y)∣0≤x<20,0≤y<21,x∈Z,y∈Z{(x, y)|0 ≤ x < 20, 0 ≤ y < 21, x ∈ Z, y ∈ Z},即横 坐标是 0到 19 (包含 0 和 19) 之间的整数、纵坐标是 0到 20 (包含 0和 20) 之 间的整数的点。
请问这些点一共确定了多少条不同的直线。
//C++ unordered_map无法使用pair和vector作为key,只能用map使用pair作为键值使用
#include <utility>
#include<iostream>
#include<map>
#include<vector>
using namespace std;
struct Point {
double x, y;
}p[25 * 25];//存下每一个点
map<pair<double, double>, int> mp;//存斜率k和截距b
int cnt, ans;
int main() {
for (int i = 0; i < 20; i++) {
for (int j = 0; j < 21; j++) {
p[cnt].x = i;
p[cnt++].y = j;
}
}
for (int i = 0; i < cnt; i++) {
for (int j = 0; j < cnt; j++) {
//两点的直线与坐标轴平行或共点
if (p[i].x == p[j].x || p[i].y == p[j].y) continue;
//斜率和截距
double k = (p[j].y - p[i].y) / (p[j].x - p[i].x);
double b = (p[j].x * p[i].y - p[j].y * p[i].x) / (p[j].x - p[i].x);
if (mp[{k, b}] == 0) {
mp[{k, b}] = 1;
ans++;
}
}
}
cout << ans+20+21 << endl;
return 0;
}第二种思路:
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <math.h>
#include <set>
using namespace std;
class Line { //直线的K个B,判断直线是不是同一条,用set来查重。
public:
double k, b;
Line(double x, double y) {
this->k = x;
this->b = y;
}
};
bool equals(double a, double b) { //改写等于号的规则,我们认为当两个数差的不是特别大,那么就是同一个数。
if (fabs(a - b) <= 1e-8)
return true;
return false;
}
bool operator<(const Line& Line1, const Line& Line2) { //如果false就不插入树,如果true就插入树中。//改写set的比较函数。注意参数必须是const &。
if (equals(Line1.k, Line2.k)) {//如果k是相等的,就按照b的顺序插入树
if (equals(Line1.b, Line2.b))//如果k和b都是相等的,就是不能插入,false。找不到一个位置让这个Line插入这颗树上。
return false;
return Line1.b < Line2.b;
}
if (equals(Line1.k, Line2.k))//如果k是相同的,就false。
return false;
return Line1.k < Line2.k;//如果k不相同,就继续比较插入。你可能会好奇,上一行的if是多余的,其实不是的,这是因为为了想要让两个相差很微小的k,先return。要不然的话,进入Line1.k<Line2.k哪怕两个k非常非常接近(1e-8)也会进行判断。
}
int main() {
set<Line> Ssq;
for (int x1 = 0; x1 < 20; x1++) {
for (int y1 = 0; y1 < 21; y1++) {
for (int x2 = 0; x2 < 20; x2++) {
for (int y2 = 0; y2 < 21; y2++) {
if (x1 == x2 && y1 == y2) //同一个点没什么好搜的。
continue;
if (x1 != x2) //避免斜率不存在的情况
{
double k = (double) (y2 - y1) / (x2 - x1);
double b = y2 - k * x2;
Ssq.insert(Line(k, b));
}
}
}
}
}
cout << Ssq.size() + 20;//没有计算过x1==x2的直线,手动加上20来计算。
return 0;
}
文章讲述了在平面直角坐标系中,通过计算不同点对确定的直线数量。通过使用map或set数据结构去重,考虑斜率和截距,以及平行于坐标轴的特殊情况,分别给出了两种C++实现的算法,一种使用map存储斜率和截距,另一种使用set处理直线类对象。最终目的是计算给定范围内所有点对确定的直线总数。

8197

被折叠的 条评论
为什么被折叠?



