Bootstrap

蓝桥杯直线(两种枚举方式)

在这里插入图片描述
考点:数学加暴力枚举

由于直线可以被表示成y = kx + b,因此我们可以枚举两个点求出斜率和截距。斜率和截距都确定了,这条直线就确定了。

由于暴力枚举有可能枚举到同一条直线,因此要去重。如果K和B都相等,证明两条直线一样,就不加了。

重点是学习枚举的方法,有两个方法:

由于要枚举两个点,可以直接枚举x1,x2,y1,y2
也可以先把所有点存下来,然后对同一段线性空间套两个for循环。

#include <iostream>
#include <map>
#include <functional>
#include <vector>
using namespace std;

map<pair<double, double>, int> m;//存斜率和截距

vector<pair<double, double>> v;//总共有20 * 19个点,开大一点点,用vector也可以 

int main()
{
	//题目给的是坐标
	//这两个循环是用来把所有的点都放进vector里面
	//其实就是让坐标相互组合
	for(double i = 0; i <= 19; i++)
		for(double j = 0; j <= 20; j++)
			v.push_back({i, j});
			
	int ans = 21 + 20;//21条横线+20条竖线 
	
	//vector里面已经是点了
	//这个时候套两层循环可以让两个点互相组合
	for(int i = 0; i < v.size(); i++)
		for(int j = 0; j < v.size(); j++)
		{
			if(v[i].first == v[j].first || v[i].second == v[j].second) continue;//横坐标相同或者纵坐标相同
			double k = (v[j].second - v[i].second) / (v[j].first - v[i].first);
			double b = (v[j].first * v[i].second - v[i].first * v[j].second) / (v[j].first - v[i].first);
			//求b的时候不能写成注释的样子,由于k是刚算出来的值
			//继续拿他做运算很容易损失精度,要把k化简掉
			//double b = (v[j].second - k * v[j].first);
			
			if(m[{k, b}] == 0) m[{k, b}] = 1, ans++; 
		} 
		
	cout << ans;
} 

总结一下什么时候可以用两层循环枚举,就是当你想要让数据里的元素彼此互相组合的时候就大胆使用把。

还可以这么写

for(int x1 = 0; x1 < n; x1++)
	for(int y1 = 0; y1 < m; y1++)
		for(int x2 = 0; x2 < n; x2++)
			for(int y2 = 0; y2 < m; y2++)
			{
				//里面逻辑一样
			}

和上面道理是一样的,相当于上面把两层循环拆开写而已。时间复杂度也没有变。

两种枚举方式都可以学习一下!!!。

答案是40257

;