题目:
平面上有 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;
}