代码改变世界

蓝桥杯[第十一届][B组]-平面切分

2022-04-04 18:25  幻霞  阅读(87)  评论(0编辑  收藏  举报

这题用到欧拉定理

所以笔者去查了一下:https://baike.sogou.com/v163464.htm?fromTitle=%E6%AC%A7%E6%8B%89%E5%AE%9A%E7%90%86&ch=frombaikevr

欧拉是个著名的各种家,提出的理论有很多,非常厉害,这也导致笔者花了不少时间去找相关的结论。

结论如下:

欧拉发现,不论什么形状的凸多面体,其顶点数V、棱数E、面数F之间总有关系V+F-E=2,此式称为欧拉公式。V+F-E即欧拉示性数,已成为“拓扑学”的基础概念。

这个和平面唯一的不同就是这是三维的结论,而该题是二维的,那么怎么办?其实我们可以把当前题目构成的图形按着一个规律升维,比如

这个图形其实我们可以把线延长然后把它们连起来(这是直线,但为了方便处理,定义一个边界,把它们连起来)

结果就是这样:

 

棕色的线是增加在面内的线,和外围面的数量相同

接下来,我们可以把它想象成一个立体的,每一个线段作为一条棱,棕色线的作为底边的立体形状。这样

它就有28条棱,16个点,根据欧拉公式V+F-E=2我们可以得出(面数 = 棱数 - 点数 +2),也就是这里的28-16+2=14个面

去掉底面刚好就是13,是原图形的答案。

首先棱数 28 = 底边(原线数*2=10)+原线数(5)+点截线产生的新棱数(原点数*2+计算时重复的点的个数*1)

点数16 = 底边的点(原线数*2=10)+原点数(6)

注 :两个线相交他们互相切割形成两条新的线(也就是这里的棱),图中因为有三线共点,所以计算时重复的点只截了新加入的线,所以只加了一条棱。

综上所述,我们算得的平面状态面的数量为: 线数 + 点数+重复的点数+1。(地面点数和边数相同直接消掉了,去掉底面-1)

在这里 5 + 6 +1 +1 =13。另外这题可以用set集合去对输入输出和重复点去重。

代码如下:

#include <bits/stdc++.h>
#include <stdlib.h>
#include <set>
#include <algorithm>
using namespace std;
set<pair<int ,int> > lines;
set<pair<double ,double> > points;
int n,m=0,num[1005]; 
int k,d;
int main() {
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    cin>>n;
    for(int i=0; i<n; i++) {
        cin>>k>>d;
        lines.insert({k,d});
    }
    for(set<pair<int,int> >::iterator l1=lines.begin(); l1!=lines.end(); l1++) {
        set<pair<double,double> > hasCut;
        for(set<pair<int,int> >::iterator l2=--lines.end(); l2!=l1; l2--) {
            if(l1->first-l2->first!=0) {//分母不为0
                double x=(l1->second -l2->second)/(double)(l2->first- l1->first);
                double y= (l1->first)*x+l1->second;
                //对点集判断,已经出现才算重复,而且一条线不能被同一个点截两次
                if(points.find({x,y})!=points.end() && hasCut.find({x,y}) == hasCut.end()) m++; 
                points.insert({x,y});
                hasCut.insert({x,y});
            }
        }
    }
    cout<<lines.size()+points.size()+m+1<<endl;
    return 0;
}

除了find函数其实还可以用count,因为集合相同元素只能有1个所以count只有0和1。