第十二届蓝桥杯 2021 C/C++组 直线

目录

题目:

题目描述:

题目链接:

思路:

核心思路:

两点确定一条直线:

思路详解:

代码:

第一种方式代码详解:

第二种方式代码详解:


题目:

题目描述:

题目链接:

直线 - 蓝桥云课

思路:

核心思路:

枚举+set去重

两点确定一条直线:

第一种推导参数的方式是直接代入两点坐标到一般式中求参数。下图展示了推导过程

第二种推导参数的方式是通过两点式方程求参数。下图展示了推导过程

思路详解:

用pair<int,int>类型来存储两个值,即在枚举的时候表示平面直角坐标系中的点。再用pair<PII,int>类型来存储三个值,PII来表示直线的前两个参数A和B,int表示直线的最后一个参数C。定义一个vector容器vec,用于存储给定平面上的所有整点的坐标,元素类型是PII,定义一个set容器s,用于存储不同的直线,set容器会自动对元素进行去重,这里的元素类型是PIII,即每一条直线用PIII来表示。然后就是从vec中提取出两个点的横纵坐标并计算得到直线参数A,B,C。这里注意:为了避免同一条直线因为系数的倍数关系而被重复存储,我们要利用__gcd()最小公倍数函数对直线方程系数进行化简。将化简后的直线信息以PIII的形式插入到set容器s中,由于set会自动去重,所以最后的结果就是set容器的大小

代码:

第一种方式代码详解:

复制代码
#include<bits/stdc++.h>  //填空题,答案是40257 
using namespace std; //思路主要就是枚举和去重,存储三个参数用pair来表示,去重用set集合 

typedef pair<int,int> PII; //将pair<int,int>类型重命名为PII,方便后续代码书写,pair用于存储两个值,
                           //这里用来表示平面直角坐标系中的点,横坐标和纵坐标都是int类型 
typedef pair<PII,int> PIII; //将pair<PII,int>类型重命名为PIII,方便后续代码书写,这里PII表示直线的
                            //一般式方程的前两个参数A和B,int表示一般式方程的最后一个参数C 

set<PIII> s; //定义一个set容器s,用于存储不同的直线,set容器会自动对元素进行去重,这里的元素类型是
             //PIII,即每一条直线用PIII来表示 

vector<PII> vec; //定义一个vector容器vec,用于存储给定平面上的所有整点的坐标,元素类型是PII 

int main()
{
	for(int i=0;i<20;i++) //由题遍历横坐标0<=i<20,纵坐标0<=j<21的所有整点,将每个点的坐标(i,j)以 
	{                     //PII的形式存入vec容器中 
		for(int j=0;j<21;j++)
		{
			vec.push_back({i,j});
		}
	}
	for(int i=0;i<vec.size();i++) //外层遍历vec中的每一个点(索引为i) 
	{
		for(int j=i+1;j<vec.size();j++) //内层循环从i+1开始遍历(索引为j),这样可以保证每两个点只 
		{                               //合一次(避免重复计算直线,点1和点2组合和点2和点1组合一样) 
			int x1=vec[i].first,y1=vec[i].second; //提取出第一个点的横、纵坐标 
			int x2=vec[j].first,y2=vec[j].second; //提取出第二个点的横、纵坐标 
			int A=y2-y1,B=x1-x2,C=x2*y1-x1*y2; //见草稿纸代入(x1,y1),(x2,y2)到Ax+By+C=0得到A,B,C 
			int gcdd=__gcd(__gcd(A,B),C);  //为了避免同一条直线因为系数的倍数关系而被重复存储
			//(例如2x+3y+4=0和4x+6y+8=0表示同一条直线),计算A,B,C的最大公约数gcdd,将直线方程系数
			//进行化简 
			s.insert({{A/gcdd,B/gcdd},C/gcdd}); //将化简后的直线信息以PIII的形式插入到set容器s中
			//由于set的自动去重特性,重复的直线不会被重复插入
			//pair类型的参数用大括号{}括起来,这里是PIII,还存在两个大括号嵌套 
		}
	}
	cout<<s.size()<<endl;
	return 0;
}
//set去重和map去重的比较:
//1.set只存储单一元素,map存储的是键值对,如果只需要去重并保留元素本身,使用set更合适,如果需要为每一
//个元素关联一个而外的值,则使用map更合适 
//2.set的使用更加简洁,因为不需要处理键值对的映射关系

第二种方式代码详解:

复制代码
#include<bits/stdc++.h>  //填空题,答案是40257 
using namespace std;

typedef pair<int,int> PII;
typedef pair<PII,int> PIII;

set<PIII> s;

vector<PII> vec;

int main()
{
	for(int i=0;i<20;i++)
	{
		for(int j=0;j<21;j++)
		{
			vec.push_back({i,j});
		}
	}
	for(int i=0;i<vec.size();i++)
	{
		for(int j=i+1;j<vec.size();j++)
		{
			int x1=vec[i].first,y1=vec[i].second;
			int x2=vec[j].first,y2=vec[j].second;
			int A=y1-y2,B=x2-x1,C=x1*y2-x2*y1;  //草稿纸上有详细推导,看似和直接代入的不一样,实际
			                                    //就是三个参数都乘了-1,还是表示同一条直线 
			int gcdd=__gcd(__gcd(A,B),C);
			s.insert({{A/gcdd,B/gcdd},C/gcdd});
		}
	}
	cout<<s.size()<<endl;
	return 0;
}
相关推荐
Cao1234567893216 分钟前
简易学生成绩管理系统(C语言)
c语言·开发语言
Yurko1331 分钟前
【C语言】全局变量、静态本地变量
c语言·学习
软行44 分钟前
LeetCode 每日一题 2845. 统计趣味子数组的数目
数据结构·c++·算法·leetcode
算法歌者44 分钟前
[C]基础12.深入理解指针(4)
c语言
小贾要学习1 小时前
【C++】继承----下篇
android·java·c++
未来可期LJ1 小时前
【Test】单例模式❗
开发语言·c++
我想进大厂1 小时前
图论---染色法(判断是否为二分图)
数据结构·c++·算法·深度优先·图论
纪元A梦1 小时前
华为OD机试真题——推荐多样性(2025A卷:200分)Java/python/JavaScript/C++/C语言/GO六种最佳实现
java·javascript·c++·python·华为od·go·华为od机试题
Yhame.2 小时前
【使用层次序列构建二叉树(数据结构C)】
c语言·开发语言·数据结构
OpenC++3 小时前
【C++QT】Buttons 按钮控件详解
c++·经验分享·qt·leetcode·microsoft