蓝桥杯2020届C++B组省赛真题 平面切分

题目:

平面上有 N 条直线,其中第 i 条直线是 y = Ai · x + Bi。
请计算这些直线将平面分成了几个部分。

【输入格式】
第一行包含一个整数 N。
以下 N 行,每行包含两个整数 Ai; Bi。

【输出格式】
一个整数代表答案。

【样例输入】

3
1 1
2 2
3 3
1
2
3
4

【样例输出】

6
1

【评测用例规模与约定】

对于 50% 的评测用例, 1 ≤ N ≤ 4, −10 ≤ Ai; Bi ≤ 10。
对于所有评测用例, 1 ≤ N ≤ 1000, −100000 ≤ Ai; Bi ≤ 100000。

分析:

在同一个平面内,如果添加的每一条直线互不相交,则每添加一条直线,就会增加一个平面;当添加一条直线时,这条直线与当前平面内已有直线每产生一个不同位置的交点时,这条直线对平面总数量的贡献会额外增多一个

大家可以结合图理解一下:

 

这道题最需要注意的是:

        他给的边可能会有重复!!!!

这道题我本来想用两个set集合,一个存边,一个存点,因为set集合会自动去重,所以不用我们再一个一个判断是否重边,但是set没有下标,不方便与之前的边进行比较。所以我采取边输入边计算的方式,一旦获取一条边的信息后就存储到数组中,再和之前已经加入的边进行匹配,判断不重边后再计算交点个数

错误代码:

#include<iostream>
#include<set>
using namespace std;
const int N = 1010;
long double L[N][2];//存储A,B 
long long ans = 1; 
int main(){
	int N;
	cin >> N;
	for(int i = 0;i < N;i++){
		cin >> L[i][0] >> L[i][1];
		bool flag = false; 
		for(int j = 0;j < i;j++){//判断是否重边
			if((L[j][0] == L[i][0]) && (L[j][1] == L[i][1])){
				flag = true;
				break;
			}
		}
		if(!flag){//若不重边,再判断交点数
			set<pair<long double,long double> > points;//记录每一条边加进来后与已有直线相交的不同位置的点 
			for(int k = 0;k < i;k++){
				long double x = (L[i][1]-L[k][1])/(L[k][0]-L[i][0]);
				long double y = L[i][0]*x+L[i][1];
				points.insert(make_pair(x,y));//set自动去重 
			}
			ans += points.size()+1;
		}
	} 
	cout << ans;
	return 0;
}

但是这么写只拿到了40分。为什么会错呢?错在哪呢?

让我们来分析一下:

我们知道两条直线有交点的前提是:两条直线相交。那如果两条直线平行,就根本不存在交点

所以要在计算之前加一个判断条件,否则分母可能为0计算出错

#include<iostream>
#include<set>
using namespace std;
const int N = 1010;
long double L[N][2];//存储A,B 
long long ans = 1; 
int main(){
	int N;
	cin >> N;
	for(int i = 0;i < N;i++){
		cin >> L[i][0] >> L[i][1];
		bool flag = false; 
		for(int j = 0;j < i;j++){//判断是否重边
			if((L[j][0] == L[i][0]) && (L[j][1] == L[i][1])){
				flag = true;
				break;
			}
		}
		if(!flag){//若不重边,再判断交点数
			set<pair<long double,long double> > points;//记录每一条边加进来后与已有直线相交的不同位置的点 
			for(int k = 0;k < i;k++){
				if(L[k][0] == L[i][0]) continue;
				long double x = (L[i][1]-L[k][1])/(L[k][0]-L[i][0]);
				long double y = L[i][0]*x+L[i][1];
				points.insert(make_pair(x,y));//set自动去重 
			}
			ans += points.size()+1;
		}
	} 
	cout << ans;
	return 0;
}

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值