解题思路
大多数人都是用找规律的方法解决。这种方法好归好,但并不是真正的意义上的解决。
几何题相对来说比较考验空间想象力、思维能力。越复杂的几何结构,其相对应的想象力、思维能力的要求也会越来越大。
对于本题,如果你是先让 N 条直线同时添加在平面上,再统计答案,那么计算起来将会十分困难。
所以我们考虑将直线一条一条加入到平面上,并考虑每条直线加入后对答案的贡献(即加入一条直线后可以额外将平面划分成产生多少个部分)。
在开始之前,我们首先要知道,当一个直线经过一个平面(区域)后,它必然会将该平面划分成两个新的区域。
起初(未添加任何直线之前)整个平面只有一个区域,那么加入了第 1 条直线后,该直线会将平面划分成两个新的区域。
现在一共有两个区域。当我们再加入第 2 条直线后,它必然会先经过一个区域,并把该区域划分成两个新的区域。接着,如果它与第 1条直线相交,那么它将会从原来的区域进入到新的区域,并也会把区域划分成两个新的区域。
假设第 2 条直线与第 1 条直线相交,那么我们加入第 3 条直线后有以下两种情况:
- 第 3 条直线与第 1、2 条直线交于两个不同的点。
- 第 3 条直线与第 1、2 条直线交于相同的点。
对于第一种情况,第 3 条直线会先后进入另外的两个区域,并将这两个区域全都划分成两个新的区域。
对于第二种情况,第 3 条直线只会从一个区域到达另一个区域,并将该区域划分成两个新的区域,之后它将不会再进入别的区域。
从上我们可得,当添加一条直线后,它首先就会将开始所在的区域划分成两个新的区域(答案个数加一);接着随着它的扩张,如果它与别的直线相交于一个点,那么它就会从原来的区域到达另一个的区域,并把另一个的区域划分成两个新的区域(答案个数加一);接着若它再与别的直线相交于另外一个点,它就将再次进入另一个区域,并将该区域也划分成两个新的区域(答案个数加一)。那么一条直线对答案的贡献 = 1 + 它与别的直线的交点个数 。
最后模拟上述过程,并统计答案即可。(注意一条边可能多次出现,别忘了去重)
ACcode:
#include<iostream>
#include<set>
using namespace std;
set<pair<int,int>>line;
int n,ans=1;
int calc(int a,int b){//那么一条直线对答案的贡献
// ==1+它与别的直线的交点个数 。
set<pair<double,double>>node;//记录(a,b)直线和其他直线交点个数
for(auto i:line){//遍历当已经存在的所有直线
int A=i.first,B=i.second;
if(A==a)continue;//平行continue(平行造成的分割体现在return的+1)
//画个简单的图就明白了
double x=1.0*(B-b)/(A-a);//交点的横坐标
double y=x*a+b;//交点的纵坐标
node.insert(make_pair(x,y));//入
}
return node.size()+1;//那么一条直线对答案的贡献==1+它与别的直线的交点个数 。
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
int a,b;
cin>>a>>b;
if(line.find(make_pair(a,b))!=line.end())//判重
//因为可能输入多个(a,b)相同的组
continue;
ans+=calc(a,b);
line.insert(make_pair(a,b));
}
cout<<ans<<"\n";
return 0;
}