精华内容
下载资源
问答
  • 如何判断点是否在圆弧上 已知一个圆弧三点,A(起点),B(中点),C(结束点)。 可以求出圆心、半径 红色的分别是圆上的起点、中点、结束点。 1、首先判断圆心到某点P的距离,是否等于半径。 如果不等于半径,则不在圆...

    如何判断点是否在圆弧上

    已知一个圆弧三点,A(起点),B(中点),C(结束点)。

    可以求出圆心、半径
    在这里插入图片描述

    红色的分别是圆上的起点、中点、结束点。

    1、首先判断圆心到某点P的距离,是否等于半径。

    如果不等于半径,则不在圆上
    

    2、连接AB和BC,连接中心点O到点P

    如果线段AB或BC其一与OP相交,则点P在圆弧上
    反之,点P不在圆弧上
    

    代码实现比较简单,就不贴了

    展开全文
  • 本文示例代码已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes后台回复地理计算也可获取本文全部代码1 简介本系列之前的文章中我们主要讨论了...实际的空间数据分析过程中,数据...

    点击蓝字关注我,有干货领取!

    f7f42d7aa258ab6efdcc03a18964a0f5.png

    本文示例代码已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes

    后台回复地理计算也可获取本文全部代码

    1 简介

    在本系列之前的文章中我们主要讨论了geopandas及其相关库在数据可视化方面的应用,各个案例涉及的数据预处理过程也仅仅涉及到基础的矢量数据处理。

    在实际的空间数据分析过程中,数据可视化只是对最终分析结果的发布与展示,在此之前,根据实际任务的不同,需要衔接很多较为进阶的空间操作,本文就将对geopandas中的部分空间计算进行介绍。

    本文是基于geopandas的空间数据分析系列文章的第8篇,通过本文你将学习到geopandas中的空间计算(由于geopandas中的空间计算内容较多,故拆分成上下两篇发出,本文是上篇)。

    2 基于geopandas的矢量计算

    geopandas中的矢量计算根据性质的不同可分为以下几类:

    2.1 构造型方法

    geopandas中的构造型方法(Constructive Methods)指的是从单个GeoSeriesGeoDataFrame中创建新的矢量数据的过程。

    譬如早在系列第一篇文章数据结构篇中就介绍过的boundsexteriorinteriorsboundarycentroidconvex_hullenvelope等属性,就基于GeoSeries计算出对应的边界、内外轮廓线、重心等新的矢量数据,这些本文不再赘述,下面我们来学习geopandas中常用的其他构造方法。

    • buffer()

    geopandas中的buffer()方法源于shapely,用于缓冲区的创建,这里给非GIS专业的读者朋友解释一下什么是空间意义上的缓冲区:

    缓冲区用于表示点、线、面等矢量数据的影响范围或服务范围,思想很简单,即为矢量数据拓展出一定宽度的边,图1展示了点、线以及面分别对应的缓冲区的示意:

    8b4f371c1d1d77f407d645ebfe11bb2a.png
    图1

    而创建缓冲区时也需要遵循一定的参数,从而决定怎样向几何对象外进行缓冲,geopandasbuffer()shapely中的buffer()方法参数一致,主要参数如下:

    distance:用于指定向外缓冲的距离,单位与矢量数据自带单位保持一致,在常见的投影坐标系如Web Mercator(EPSG:3857)下就是以米为单位,因此需要注意一定要先将矢量数据转换为合适的投影坐标系之后,再进行缓冲区分析才是合理有效的

    resolution:因为在创建缓冲区时,对于构成矢量对象的每一个点,都会以对应点为中心向外创建半径=缓冲区距离的圆,而Polygon类型始终是由有限个点所构成的,因此需要近似拼接出圆形的轮廓,resolution参数就用于决定每个四分之一圆弧上使用多少段连续的线段来近似拼接以表示圆的形状,默认参数值为16,足以近似模拟圆面积的99.8%

    下面我们分别对点、线以及面绘制不同resolution参数取值下缓冲前后的对比图:

    8a4c45556ce9523084560e6d063fb08c.png
    图2

    可以看出,resolution参数对最终形成的缓冲区形态影响较大,但默认16的参数下已经可以较准确地逼近圆形,且缓冲距离还可以设置为负数,即几何对象向内收缩:

    # 分别绘制多边形、多边形正向缓冲区、多边形负向缓冲区
    ax = gpd.GeoSeries([polygon,
                        polygon.buffer(distance=1),
                        polygon.buffer(distance=-0.25)]) \
            .plot(alpha=0.2)
    ax.axis('off')

    plt.savefig('图3.png', dpi=300, bbox_inches='tight', pad_inches=0)
    45b8dc796c2b72cb093f989a8d5d357b.png
    图3

    在本系列文章第一篇中介绍过shapely对矢量数据格式的合法性有一定规定,如多边形不能自交叉,可以通过is_valid()方法判断几何对象是否合法。

    buffer()有一个隐藏功能就是其可以通过对非法的几何对象创建距离为0的缓冲区来修正构成矢量对象的点的不合理连接顺序,从而使得矢量对象变为合法的:

    5b1deb665dc7d0b97102f43c09d897ab.png
    图4
    • total_bounds

    total_bounds你应该不会感到陌生,在前面很多篇文章中我们都使用到它来限定图像的画幅范围,其返回依次记录了整列矢量数据所在最小矩形区域左下角x、左下角y、右上角x以及右上角y的numpy数组:

    geom = gpd.GeoSeries([shapely.geometry.Point([00]),
                          shapely.geometry.Point([01]),
                          shapely.geometry.Polygon([(11), (1.51), (1.251.25)])])

    ax = geom.plot(alpha=0.4)

    # 绘制total_bounds范围
    ax = gpd.GeoSeries([shapely.geometry.box(*geom.total_bounds.tolist())]) \
            .plot(ax=ax,
                  alpha=0.1,
                  color='red')

    ax.axis('off')
    3b88c22385e2341d65dfff4d6c6b2290.png
    图5
    • simplify()

    当原始的矢量数据因为形状复杂,包含的点较多时,会导致其文件体积较大,如果我们需要在在线地图上叠加它们,太大体积的矢量数据不仅会拖慢网络传输速度,也会给图形的渲染带来更大的压力。

    这时对矢量数据进行简化就非常有必要,geopandas中沿用shapely中的simplify()方法,帮助我们对过于复杂的线和面进行简化,和QGIS中简化矢量的方法一样,simplify()使用了科学的Douglas-Peucker算法,基于预先设定的阈值,在递归判断的过程中删掉所有小于的点,其过程示意如图6:

    35f957eb72a53d76778155cded633f80.gif
    图6

    譬如我们这里基于-1到1之间的均匀分布,创建一条上下波动的折线,再用simplify()来简化它:

    import numpy as np
    import matplotlib.patches as mpatches

    np.random.seed(10# 固定随机数种子

    # 创建线
    line = shapely.geometry.LineString([(_, np.random.uniform(-11)) for _ in range(10)])

    # 绘制简化前
    ax = gpd.GeoSeries([line]).plot(color='red')

    # 绘制简化后
    ax = gpd.GeoSeries([line]).simplify(tolerance=0.5).plot(color='blue'
                                                            ax=ax,
                                                            linestyle='--')

    # 制作图例映射对象列表
    LegendElement = [plt.Line2D([], [], color='red', label='简化前'),
                     plt.Line2D([], [], color='blue', linestyle='--', label='简化后')]

    # 将制作好的图例映射对象列表导入legend()中,并配置相关参数
    ax.legend(handles = LegendElement, 
              loc='lower left'
              fontsize=10)

    ax.set_ylim((-2.51))
    ax.axis('off')
    plt.savefig('图7.png', dpi=300, bbox_inches='tight', pad_inches=0)
    3b6f8f6ae404d0b8ef533f1b43b514fa.png
    图7

    可以看到在预设的阈值下,对应simplify()中的参数tolerance=0.5,折线得到有效地简化,这在搭建web GIS平台要渲染矢量数据时非常有效,有效简化后的矢量数据可以在不损失太多视觉感知到的准确度的同时,带来巨大的性能提升。

    • unary_union

    我们都知道,不管是GeoSeries还是GeoDataFrame,其每一行数据都代表独立的shapely矢量要素,而通过unary_union属性,我们可以将一整列矢量合并为单独的一个shapely矢量对象,从而方便我们进行一些其他的操作:

    fef86ab9b438100db5fc317444613238.png
    图8

    并且如果原始数据中存在互相存在重叠的矢量对象,通过unary_union之后,返回的shapely对象会自动对存在重叠的矢量对象进行融合,这一点可以方便我们的很多日常操作:

    82da3f9ba14f29fcfd6d3143c41f73bf.png
    图9

    2.2 仿射变换

    geopandas中封装了几种常见的仿射变换操作,如旋转等:

    • rotate()

    rotate()对矢量列中的每个要素分别进行旋转操作,其主要参数如下:

    angle:数值型,用于指定需要旋转的角度

    origin:用于指定旋转操作的中心,默认为center,是矢量对象bbox矩形范围的中心,centroid表示矢量对象的重心,或者也可以传入格式如(x0, y0)的坐标元组来自定义旋转中心

    要注意的是rotate()旋转方向是逆时针,如下面的例子,红色是旋转90度之后的美国:

    ax = world.query("iso_a3 == 'USA'").plot(color='blue',
                                             alpha=0.4)
    ax = world.query("iso_a3 == 'USA'").rotate(angle=90,
                                               origin='center') \
                                       .plot(color='red',
                                             ax=ax,
                                             alpha=0.4)
    plt.savefig('图10.png', dpi=300, bbox_inches='tight', pad_inches=0)
    23e74a2ee02633e2e417af09943dd4aa.png
    图10
    • scale()

    scale()方法用于对矢量对象进行各个维度上的放缩操作,其主要参数如下:

    xfact:数值型,表示对x维度上进行放缩的因子,默认为1即不放缩,小于1则缩放,大于1则放大

    yfact:同xfact,控制y维度上的放缩因子

    origin:同scale()中的origin,用于确定缩放中心

    如下面的例子,我们在x以及y维度上对美国进行0.5倍放缩,红色代表缩放之后:

    ax = world.query("iso_a3 == 'USA'").plot(alpha=0.4)

    ax = world.query("iso_a3 == 'USA'").scale(xfact=0.5, yfact=0.5) \
                                       .plot(color='red',
                                             alpha=0.5,
                                             ax=ax)

    plt.savefig('图11.png', dpi=300, bbox_inches='tight', pad_inches=0)
    c968c80a47db367d5354f54aa1762b63.png
    图11
    • translate()

    translate()用于实现矢量对象的平移操作,其主要参数有xoffyoff,分别控制在x维度和y维度上的平移距离(与对应的投影单位保持一致):

    a430208bd676d6ebb6a84f79ee55e3c1.png
    图12

    2.3 叠加分析

    geopandas基于shapely中的overlay(),为GeoDataFrame赋予了同样的可以作用到整个矢量列的overlay(),使得我们可以对两个GeoDataFrame中全部的矢量对象两两之间进行基于集合关系的叠加分析(如图13):

    a1ffb145a5e898c19f3235c00e5bcb6d.png
    图13

    overlay()中的主要参数如下:

    df1:GeoDataFrame,作为输入的第一个矢量数据集

    df2:GeoDataFrame,作为输入的第二个矢量数据集

    how:字符型,用于声明空间叠加的类型,对应图13,有'intersection''union''symmetric_difference''difference',以及额外的'identity',他们之间的区别下文会进行详细介绍

    keep_geom_type:bool型,当df1df2矢量类型不同时(譬如面与线数据之间进行叠加分析),用于决定在叠加分析产生结果中,是否只保留与df1矢量类型相同的记录,默认为True

    首先我们构造示例矢量数据,以方便演示overlay()不同参数下结果的区别:

    polygon1 = gpd.GeoDataFrame({
        'value1': [12],
        'geometry': [shapely.geometry.Polygon([(10), (30), (310), (110)]),
                     shapely.geometry.Polygon([(60), (80), (810), (610)])]
    })

    polygon2 = gpd.GeoDataFrame({
        'value2': [34],
        'geometry': [shapely.geometry.Polygon([(-13), (-15), (105), (103)]),
                     shapely.geometry.Polygon([(-16), (-18), (108), (106)])]
    })

    ax = polygon1.plot(color='red', alpha=0.4)
    ax = polygon2.plot(color='grey', alpha=0.4, ax=ax)
    ax.axis('off')
    plt.savefig('图14.png', dpi=300, bbox_inches='tight', pad_inches=0)
    8fec45cf7ab206e2883abec899ecd061.png
    图14

    接下来我们将其中红色部分对应的GeoDataFrame作为df1,灰色部分作为df2,来比较overlay()中不同参数对应的效果:

    • how='union'

    首先我们设置how='union',对polygon1polygon2进行叠加分析:

    overlay_result = gpd.overlay(df1=polygon1,
                               df2=polygon2,
                               how='union')
    overlay_result

    得到的结果如图15:

    5c20a63186345968b05935b120399e75.png
    图15

    可以发现,有些行存在缺失值而有些行又是完整的,我们分别绘制出这两类记录行:

    # 存在缺失值的行
    ax = overlay_result[overlay_result.isna().any(axis=1)] \
                       .plot(color='grey')

    # 不存在缺失值的行
    ax = overlay_result[~overlay_result.isna().any(axis=1)] \
                       .plot(color='blue',
                             ax=ax)

    ax.set_xlim((-110))
    ax.set_ylim((010))
    plt.savefig('图16.png', dpi=300, bbox_inches='tight', pad_inches=0)
    290ebe8bd9f38445730b97ea8421fbab.png
    图16

    how='union'下,叠加分析的结果会包含所有存在相交的部分,以及df1df2各自剩下的不相交的部分,如图中蓝色部分即为df1df2相交从而不存在缺失值的部分,而剩余的灰色部分因为没有相交,无法获得来自另一个GeoDataFrame的属性值,所以返回出来的结果会在对应的字段下填充为缺失值。

    • how='intersection'

    how='intersection'参数下对polygon1polygon2进行叠加分析:

    overlay_result = gpd.overlay(df1=polygon1,
                               df2=polygon2,
                               how='intersection')
    overlay_result
    f00866d32058ddee8f3d4e0ebd611574.png
    图17

    这时返回的结果中不再带有缺失值,因为intersection只保留df1df2彼此相交的部分:

    ax = overlay_result.plot()

    ax.set_xlim((-110))
    ax.set_ylim((010))
    plt.savefig('图18.png', dpi=300, bbox_inches='tight', pad_inches=0)
    ed72e048e42208ee1ea968d941ae5e18.png
    图18
    • how='difference'

    how='difference'参数下对polygon1polygon2进行叠加分析:

    overlay_result = gpd.overlay(df1=polygon1,
                                 df2=polygon2,
                                 how='difference')
    overlay_result
    7ea11f13c476ac9beee4bbe1e49e264a.png
    图19

    这时返回的结果中不再有value2字段,结合图13可以知晓在how='difference'下的返回结果与Arcgis中的擦除功能一样,返回的是df1中不与df2相交的部分,且以Multi的形式保留被切割开来的碎片矢量:

    ax = overlay_result.plot()

    ax.set_xlim((-110))
    ax.set_ylim((010))
    plt.savefig('图20.png', dpi=300, bbox_inches='tight', pad_inches=0)
    c5a8cbc80ae4f509f8371a35b0527d42.png
    图20
    • how='symmetric_difference'

    'symmetric的意思是对称的,而在how='symmetric_difference'条件下,与Arcgis中的交集取反功能相同,两个df中不相交的部分都会被返回:

    overlay_result = gpd.overlay(df1=polygon1,
                                 df2=polygon2,
                                 how='symmetric_difference')
    overlay_result
    1e362e2d5bdbd46f3b071b62fd15d850.png
    图21
    00d59cddb774ba011c7aad4cecb593bd.png
    图22
    • how='identity'

    最后我们来看看how='identity',对应Arcgis中的标识功能:

    overlay_result = gpd.overlay(df1=polygon1,
                                 df2=polygon2,
                                 how='identity')
    overlay_result
    74b931a22dc78387bd20214eb0a8a881.png
    图23

    为了方便理解,我们同样分别绘制出存在缺失值的行以及不存在缺失值的行:

    # 存在缺失值的行
    ax = overlay_result[overlay_result.isna().any(axis=1)] \
                       .plot(color='grey')

    # 不存在缺失值的行
    ax = overlay_result[~overlay_result.isna().any(axis=1)] \
                       .plot(color='blue',
                             ax=ax)

    ax.set_xlim((-110))
    ax.set_ylim((010))
    plt.savefig('图24.png', dpi=300, bbox_inches='tight', pad_inches=0)
    b0a941f0f5e23f32ea3c58e2d1e3830d.png
    图24

    从图24中可以看出,在how='identity'条件下,所有df1中不与df2相交的部分,以及两者相交的部分作为返回结果,且每个相交的部分都变为单独的要素带上所有涉及的属性字段,而df1中不涉及相交的部分则仍然以Multi的形式被返回。

    • keep_geom_type

    有些时候我们需要做的不仅仅是面与面之间的叠加分析。

    比如在计算路网相关的指标时,我们可能会需要与目标区域存在叠置关系的部分路网,这就存在面与线之间的叠加分析。

    参数keep_geom_type就用于设定最终返回的矢量数据类型是否必须与df1对应的类型相同,下面我们构造示例数据来学习keep_geom_type参数的作用:

    9f2a268d19e0ac6eb265f6918e067bac.png
    图25

    True和False下结果如图26所示:

    e7a7188ef19fe048ca5b9a2a3a376ca8.png
    图26

    其中GeometryCollection类型代表多类型要素集合,比如这里叠加分析的结果包含了一条线和一个点:

    f12f653690b2a84f30095bfda20063ba.png
    图27

    在实际工作中,可以根据具体需要来选择使用对应的参数组合来进行叠加分析。

    2.4 空间融合与拆分

    有时候我们希望对矢量数据按照某些字段进行分组,再分别对非矢量列与矢量列进行聚合及合并,类似于pandas中的groupby.agg()

    而有些时候我们希望把矢量类型为Multi-xxx的记录行拆分成独立要素行,譬如将Multi-Polygon拆分成Polygon组成的若干行。通过geopandass中的dissolve()explode()方法,我们就可以实现上述功能:

    • dissolve()

    dissolve()用于对矢量数据进行融合,可以理解为对矢量数据进行groupby+agg操作,即指定的单个或多个字段值相等的分到一组,对非矢量字段进行指定规则的聚合计算,对矢量列进行融合,其主要参数如下:

    by:用于指定分组所依据的字段,单个字段传入列名字符串,多个字段传入列名列表

    aggfunc:对分组字段外的其他非矢量列采取的聚合方式,与pandas中的agg一致,默认为first,也可以像agg那样传入字段和函数一一对应的字典来分别聚合不同的列

    as_index:bool型,用于设定是否在返回的结果中将分组依据列作为索引,默认为True

    我们以world数据集为例,为了方便演示我们首先新增字段less_than_median_gdp,用于判断对应的国家GDP是否小于世界中位数水平:

    8c989db8a7e7642380d8d834211c301c.png
    图28

    接着我们以国家对应大洲列continent为分组依据,并对人口和GDP列进行求和,如图29所示,在非矢量列得到对应的聚合计算之后,矢量列也被融合为Multi-Polygon

    2a534770499d6136dfac1bb1e7e7c844.png
    图29
    • explode()

    explode()功能与dissolve()相反,用于将Multi-xxxGeometry-Collection类型的数据从一行拆分到多行,如下面的例子,非矢量字段会自动填充到每一行:

    43e483421081f31fee42316bea86264b.png
    图30

    以上就是本文的全部内容,关于更多geopandas空间计算的内容,我们将在下一篇中继续讨论,敬请期待!

    28c76ea8266feaa4f90c658c5746945d.png

    如需联系EasyShu团队

    请加微信:EasyCharts

    微信公众号【EasyShu】博文代码集合地址

    https://github.com/Easy-Shu/EasyShu-WeChat

    数据可视化之美系列书籍

    619aae00c7acc54d742cb5911ccfd9bb.png

    《Python数据可视化之美》-配套源代码下载地址

    Github

    https://github.com/Easy-Shu/Beautiful-Visualization-with-python

    《R语言数据可视化之美》-增强版配套源代码下载地址

    Github

    https://github.com/Easy-Shu/Beautiful-Visualization-with-R

    fa7753acfa4fed8d5dd76a73899198bf.png

    展开全文
  • (2)进行 求解 数组 (3)比较 与 现在来考虑如何判定两棵无根树是否同构: 假设我们现在有两棵无根树 同构,那么我们 树中选一点 作为 树的根,那么 树中一定存在一点 ,使得 树以 为根与 树以 为根同构。...

    (一)需要掌握的前置知识:

    (1)素数筛法:埃氏筛或者欧拉筛均可以。

    以下为欧拉筛:

    const int maxn=100100;
    int p[maxn],cnt=0;
    bool ha[maxn];
    void Prime(void){
        ha[1]=true;
        for(int i=2;i    {
            if(!ha[i]) p[++cnt]=i;
            for(int j=1;j<=cnt&&i*p[j]        {
                ha[i*p[j]]=true;
                if(i%p[j]==0break;
            }
        }
    }

    (2)一般的哈希知识。

    (3)基本的树上 遍历整棵树。

    (4)树上重心的求解:

    树的重心: 找到一个点 , 以点 为根时,其所有的子树中最大的子树节点数最少,那么这个点 就是这棵树的重心。(以重心为根时,最大子树最小)

    性质:

    (1)树中所有点到某个点的距离和中,到重心的距离和是最小的,如果有两个重心,他们的距离和一样。(这里树的边权都定义为 )

    (2)把两棵树通过一条边相连,新的树的重心在原来两棵树重心的连线上。

    (3)一棵树添加或者删除一个节点,树的重心最多只移动一条边的位置。

    (4)一棵树最多有两个重心,且相邻。

    (5)删除重心后所得的所有子树,节点数不超过原树的1/2。

    其他说明:判定树同构有多种方法,且树同构的哈希也有多种方法,接下来仅介绍一种常用的哈希方法,其他的哈希方法类推即可。

    (二)例题一:洛谷--P5043 【模板】树同构([BJOI2015]树的同构)

    题目连接

    题面截图:

    044262510b7488b40e57bd8e19db429f.png
    在这里插入图片描述

    题意:

    给定 棵无根树,对于第 棵无根树寻找 中与第 棵无根树同构的最小的无根树的编号。

    题解:

    根据题意,我们很容易写出伪代码:

    for(int i=1;i<=m;i++)
    {
        for(int j=1;j<=i;j++)
        {
            if(第 i 棵树与第 j 棵树同构) //找到与第 i 棵树同构的树
            {
                printf("%d\n",j);
                break;
            }
        }
    }

    现在问题的关键转化为判断两棵无根树是否同构。

    先来考虑问题的简化版:两个有根树如何判定是否同构。

    类似于字符串的哈希,我们给树的每个节点附一个权值,记为

    我们设 。这里 取自然溢出,即对 取模。

    其中 表示在有根树中  的儿子节点。 函数。

    数组是我们取前 ()个质数,再随机打乱后的数组。

    随机打乱 数组。

    random_shuffle(p+1,p+k+1);//k可以自己选定

    表示 子树的大小。

    那么如果判定两个有根树同构呢,我们认为 如果,那么就可以认为两棵树同构。事实上虽然 有可能两棵树不一定同构,如果在确认算法正确且时间允许的情况下,我们可以多哈希来判定树的同构。事实上多哈希来判定同构,冲突的概率就极低了,数据一般也不容易构造。

    现在我们来总结一下怎样判定两棵根分别为 的树的同构的方法:

    (1)求解 数组,利用埃氏筛或者欧拉筛。

    (2)在树上进行 求解 数组

    (3)比较

    现在来考虑如何判定两棵无根树是否同构:

    假设我们现在有两棵无根树 同构,那么我们在 树中选一点 作为 树的根,那么在 树中一定存在一点 ,使得  树以 为根与 树以 为根同构。

    相反的,如果我们在 树中选一点 作为 树的根,那么在 树中如果存在一点 ,使得  树以 为根与 树以 为根同构,那么两棵 无根树 同构。

    我们对 树中的某一点 ,去找在 树中是否能存在一个点 ,使得 树中以点 为根的树与 树中以点 为根的树同构。

    那么我们能得到判定无根树同构的算法:

    对于 树中的某一点 ,求出 树中以 为根的 ,然后在 树中寻找,是否存在一点 ,使得 树中以 为根的 等于 树中以 为根的 。若存在,则说明 同构,否则不同构。

    为了方便判别,我们可以有以下处理:

    对于 树的每个节点 ,求出 树中以 为根的 ,将这些 保存至 数组。

    对于 树的每个节点 ,求出 树中以 为根的 ,将这些 保存至 数组。

    两数组按照相同的排序规则排序 (都升序或者都降序),那么如果最终 两棵树的节点数相同且 两数组对应位置相同,那么认为 两棵树同构。

    回到本题:

    我们对 棵树,对于第 棵树,我们保存下以 为根的  值,记为 ,然后再对 数组进行排序。

    判定两棵树是否同构的时候只需要比较两棵树的大小和 两个数组即可。

    空间复杂度 ,时间复杂度 。(因为 同级别,就都当作 来计算)

    因为这里节点数 比较小,所以我们直接打质数表即可。

    代码:

    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #define ll long long
    #define pr make_pair
    #define pb push_back
    #define lc (cnt<<1)
    #define rc (cnt<<1|1)
    using namespace std;
    const int inf=0x3f3f3f3f;
    const ll lnf=0x3f3f3f3f3f3f3f3f;
    const double dnf=1e15;
    const int mod=1e9+7;
    const int maxn=55;
    int head[maxn],ver[maxn<<1],nt[maxn<<1];
    int n[maxn],si[maxn],tot=1;
    unsigned ll ha[maxn][maxn],f[maxn];
    int p[]={0,2,3,5,7,11,13,17,19,23,29,31,37,
             41,43,47,53,59,61,67,71,73,79,83,89,97,
             101,103,107,109,113,127,131,137,139,149,
             151,157,163,167,173,179,181,191,193,197,
             199,211,223,227,229};

    void init(void){
        memset(head,0,sizeof(head));
        tot=1;
    }

    void add(int x,int y){
        ver[++tot]=y,nt[tot]=head[x],head[x]=tot;
    }

    void dfs(int x,int fa){
        f[x]=si[x]=1;
        for(int i=head[x];i;i=nt[i])
        {
            int y=ver[i];
            if(y==fa) continue;
            dfs(y,x);
            f[x]+=f[y]*p[si[y]];
            si[x]+=si[y];
        }
    }

    bool check(int i,int j){
        for(int k=1;k<=n[i];k++)
        {
            if(ha[i][k]!=ha[j][k]) return false;
        }
        return true;
    }

    int main(void){
        random_shuffle(p+1,p+50+1);
        int m,fa;
        scanf("%d",&m);
        for(int i=1;i<=m;i++)
        {
            init();
            scanf("%d",&n[i]);
            for(int j=1;j<=n[i];j++)
            {
                scanf("%d",&fa);
                if(fa) add(fa,j),add(j,fa);
            }
            for(int j=1;j<=n[i];j++)
            {
                dfs(j,0);
                ha[i][j]=f[j];
            }
            sort(ha[i]+1,ha[i]+n[i]+1);
        }
        for(int i=1;i<=m;i++)
        {
            for(int j=1;j<=i;j++)
            {
                if(n[i]==n[j]&&check(i,j))
                {
                    printf("%d\n",j);
                    break;
                }
            }
        }
        return 0;
    }

    虽然 的算法足够通过本题,但是如果 级别的就不能再处理了,考虑优化。

    思考:我们为什么要求第 棵无根树分别以每个节点  为根的  ?

    因为 两棵无根树 同构 等价于 对于 中以某一点 为根的有根树, 中存在以 为根的有根树与 中以 为根的有根树同构。我们需要在 中找到

    那么我们能不能快速在中分别找到一点 ,使得 是相对应的,即 让 是否同构等价于以为根的有根树与以为根的有根树是否同构。

    能不能找到这样的两点 呢? 重心!重心!重心!

    于是判定同构的条件转化为:

    两棵无根树 是否同构,等价于他们以重心为根的有根树是否同构。

    考虑一下为什么?若重心唯一,那么两棵无根树 同构时的重心必定对应;若重心都不唯一,那么两棵无根树 同构时两棵树的重心也一一对应。

    即,若两棵树同构,那么重心为根的树一定是同构的。如果重心为根的树是同构的,那么两棵树一定是同构的。

    那么求解无根树是否同构的方法可以优化为以下做法:

    (1)求解树 的重心,重心至多有两个。

    (2)求解树 以重心为根的

    (3)判断是否同构。

    回到本题:

    我们只需要求解第 棵树的重心,然后求解重心的 即可。

    空间复杂度 ,时间复杂度

    代码:

    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #define ui unsigned int
    #define ll long long
    #define llu unsigned ll
    #define ld long double
    #define pr make_pair
    #define pb push_back
    #define lc (cnt<<1)
    #define rc (cnt<<1|1)
    #define len(x)  (t[(x)].r-t[(x)].l+1)
    #define tmid ((l+r)>>1)
    #define fhead(x) for(int i=head[(x)];i;i=nt[i])
    #define max(x,y) ((x)>(y)?(x):(y))
    #define min(x,y) ((x)>(y)?(y):(x))
    using namespace std;

    const int inf=0x3f3f3f3f;
    const ll lnf=0x3f3f3f3f3f3f3f3f;
    const double dnf=1e18;
    const double alpha=0.75;
    const int mod=1e9+7;
    const double eps=1e-8;
    const double pi=acos(-1.0);
    const int hp=13331;
    const int maxn=55;
    const int maxm=100100;
    const int maxp=100100;
    const int up=1100;
    int head[maxn],ver[maxn<<1],nt[maxn<<1];
    int n[maxn],si[maxn],dp[maxn],tot=1,rt1,rt2,nown;
    llu f[maxn],rt1f[maxn],rt2f[maxn];
    int p[]={0,2,3,5,7,11,13,17,19,23,29,31,37,
             41,43,47,53,59,61,67,71,73,79,83,89,97,
             101,103,107,109,113,127,131,137,139,149,
             151,157,163,167,173,179,181,191,193,197,
             199,211,223,227,229};

    void init(void){
        memset(head,0,sizeof(head));
        tot=1;
        rt1=0,rt2=0;
    }

    void add(int x,int y){
        ver[++tot]=y,nt[tot]=head[x],head[x]=tot;
    }

    void dfs1(int x,int fa){
        si[x]=1,dp[x]=0;
        for(int i=head[x];i;i=nt[i])
        {
            int y=ver[i];
            if(y==fa) continue;
            dfs1(y,x);
            si[x]+=si[y];
            dp[x]=max(dp[x],si[y]);
        }
        dp[x]=max(dp[x],nown-si[x]);
        if(rt1==0||dp[x]0;else if(dp[x]==dp[rt1]) rt2=x;
    }void dfs2(int x,int fa){
        f[x]=si[x]=1;for(int i=head[x];i;i=nt[i])
        {int y=ver[i];if(y==fa) continue;
            dfs2(y,x);
            f[x]+=f[y]*p[si[y]];
            si[x]+=si[y];
        }
    }bool check(int i,int j){return (rt1f[i]==rt1f[j]&&rt2f[i]==rt2f[j])||(rt1f[i]==rt2f[j]&&rt2f[i]==rt1f[j]);
    }int main(void){
        random_shuffle(p+1,p+50+1);int m,fa;scanf("%d",&m);for(int i=1;i<=m;i++)
        {
            init();scanf("%d",&n[i]);for(int j=1;j<=n[i];j++)
            {scanf("%d",&fa);if(fa) add(fa,j),add(j,fa);
            }
            nown=n[i];
            dfs1(1,0);if(rt1!=0) dfs2(rt1,0),rt1f[i]=f[rt1];if(rt2!=0) dfs2(rt2,0),rt2f[i]=f[rt2];
        }for(int i=1;i<=m;i++)
        {for(int j=1;j<=i;j++)
            {if(check(i,j))
                {printf("%d\n",j);break;
                }
            }
        }return 0;
    }
    fdc120acac733064a64d82e5781e2bcd.gif

    温馨提示

    如果你喜欢本文,请分享到朋友圈,想要获得更多信息,请关注ACM算法日常

    65b53de54517164c353773b70a5006c2.png

    点赞的时候,请宠溺一点
    展开全文
  • 往期回顾:人教版数学二1.1《认识厘米》视频+练习人教版数学二1.2《认识米 》视频+练习人教版数学二1.3《认识线段》视频+练习人教版数学二1.4《确定长度单位》视频+练习人教版数学二2.1《不进位加法》视频...

    往期回顾:

    人教版数学二上1.1《认识厘米》视频+练习

    人教版数学二上1.2《认识米 》视频+练习

    人教版数学二上1.3《认识线段》视频+练习

    人教版数学二上1.4《确定长度单位》视频+练习

    人教版数学二上2.1《不进位加法》视频+练习

    人教版数学二上2.2《进位加法》视频+练习

    人教版数学二上2.3《不退位减法》视频+练习

    人教版数学二上2.4《退位减法》

    人教版数学二上2.5《求比一个数少几的数》

    人教版数学二上2.6《连加、连减》

    人教版数学二上2.7《加减混合》

    人教版数学二上3.1《角的初步认识 》

    人教版数学二上3.2《直角的认识》

    人教版数学二上3.3《锐角和钝角》

    3039ec4b1983ffc45da0c339cd23aeed.png

    c6c52be752ab072a85b0ad883414756c.png

    ec1c06ee58b1daeff8c04362fbc011f5.png

    知识点

    1、用三角尺画直角的方法:三角尺的直角边,沿着一画是直角(一点、二线、三标记。)

    2、所有的直角大小都相等。数学书的封面上有4个角,4个都是直角。

    3、怎样在一张不规则的纸中得到一个直角?

    答:拿一张不规则的纸,先上下对折,再左右对折可以得到直角。

    4、数角的个数时,可以先数单个的角,再数由两个单个的角组成的角,再数由三个单个的角组成的角,依次这样数下去,加在一起就是一共有多少个角。

    5、拼角:一(角)加一锐( 角 )就可以拼成一个钝角

    6、当钟面上是(3)时整和(9)时整时,时针和分针都成(直)角

    同步练习

    b816ea3eb3688646574ad6cfdd74db94.png

    参考答案

    06ac250adaa74a48cc2a2ce398badb34.png

    教学设计

    教学目标

    1.更加熟悉角,能正确判断直角、锐角和钝角。

    2.熟练借助三角尺上的直角比较角的大小。

    3.会画直角。

    重点难点

    重点:正确判断直角、锐角和钝角。

    难点:比较角的大小,会画角。

    教具学具

    三角尺、课件。

    教学过程

    问题情境

    :同学们,这段时间我们认识了图形家族的新朋友——,你了解它了吗?

    【设计意图:借助谈话引入新课,激发学生探究的兴趣,吸引学生的注意力】

    自主探究

    1.认识角。

    :在小组内说说你认识的角,然后把你们小组的看法整理好,与大家交流。

    学生在小组内交流自己的收获,教师巡视了解情况。

    1:我知道角是由一个顶点和两条边组成的。

    2:我知道角有直角、锐角和钝角。

    3:我觉得生活中常见的角是直角,如桌子角是直角,教材封面上的角是直角,门上也有直角,黑板也有直角,等等,总之生活中的直角很多。

    4:我知道三角尺上有直角,我们可以借助三角尺上的直角比较角的大小。

    5:,比直角大的角是钝角,比直角小的角是锐角。

    ……

    :同学们说得都非常好,刚才有的同学说到了比较角的大小,老师想知道你是怎么比较角的大小的?

    :在比较角的大小时,我们先让角的顶点和三角尺上直角的顶点重合,再让角的一条边与三角尺上直角的一条边重合。如果角的另一条边在直角的里面就说明比直角小,是锐角;如果角的另一条边在直角的外面就说明比直角大,是钝角。

    :听同学们这样一说,你是不是更明白了?下面来检验一下。

    (课件出示教材第43页第1题图片)

    :指一指哪里有角。

    学生看图后指出每个物品中的角,教师适时给予评价,以鼓励性评价为主。

    :你能说出刚才找到的角哪些是直角、锐角,钝角吗?

    学生按要求分别找角,教师组织学生做评判,判断是否正确。

    2.画角。

    :同学们,在刚才识别角的过程中表现得很好,那么你们会画角吗?谁来告诉大家怎样画角呢?说说你的小窍门。

    1:画角的时候就是从一个点起,用三角尺向不同方向画两条线,就画成一个角。

    2:如果要画直角,应该让三角尺上的直角顶点与这一个点重合,一条直角边与我们所画的线重合,最后沿三角尺的另一条直角边画好角的另一边,这样就画出了直角。

    :(课件出示教材第44页第11)现在就请同桌两个人各自画一个角,然后互相说一说画的是什么角。

    学生操作交流,教师巡视指导,了解情况。

    【设计意图:给学生创造宽松的氛围,并给学生足够的时间去探讨、交流。在活动中梳理知识,在交流与探究中总结提高】

    总结提升

    :经过这节课的总结,你有什么收获呢?

    板书设计

    ad0be6f16cf19d6b03381eab308ae6ab.png

    好资源可以分享给更多的人哦,欢迎转发、点在看,让更多的人受益,谢谢支持哦!

    ◆说明:平台资源仅供学习,严禁商业用途,版权归原作者所有。如有侵权烦请告知,我们会立即删除并表示歉意。谢谢!

    53ce9a2582e23c5624982a6648835c81.png

    展开全文
  • 》[¹]系列,当时是利用下班公交的时间刷的。说下那时的感受吧,有些知识还真不知道,就感觉好牛批,确实有一种被灵魂拷问的感觉。最最可怕的是那时候还没有意识到自己的基础这么差,只是死记着一些零散的知识...
  • 任何一个体育联盟想要取得长期...本文将挑选出NBA历史最具影响力的十次规则改动。10、禁止联防(1947)所谓的联防,值的是以固定队员固定防守一定区域的方式进行防守,防球更胜防人。联盟成立没多久,NBA管理层...
  • 圆这个章节,知识较多,为了更好的...圆弧:圆任意两间的部分叫做圆弧,简称弧。大于半圆的弧称为优弧,小于半圆的弧称为劣弧。弦:连接圆任意两的线段叫做弦,经过圆心的弦叫做直径。圆心角:顶点圆...
  • 对于圆的轨迹长度,只要确定了轨迹圆弧对应的圆心角,即可求解,而对于线段的最值问题,一般而言,也是分为两类:定点到圆动点的最值问题和传说中的阿氏圆,关于最值问题,下次再出一个专题来讲一讲,今天重点把...
  • 这里不涉及什么复杂的看配料表、看营养成分表、看包装有没有浮夸的宣传语之类,就是观察食品包装的外形,就可判断是否变质,很简单。美女查看包装一、充气类小食品:这类食品基本是塑料袋包装,外观看起来都是气鼓...
  • 」这是丁的第452期推送每周一三五七晚8更新▼-眼型审美-今天来聊大家很关心的一个显老特征——挑眼。这个特征很多女生都不太喜欢,因为这种眼型很多人的印象里容易显凶显成熟。典型的挑眼代表张雨绮,一直...
  • 如题,我用Graphics的DrawRac画了一段圆弧,现在想知道该圆弧上某一点的坐标。我的思路是判断鼠标是否在当前... 我看CSDN上判断点在直线上都用了一大堆海伦公式什么的,难道判断真的这么复杂吗?有没有什么快捷的方法
  • 常用的期货技术分析指标中,比如MACD、KDJ、布林线等等,这些都是周期K线图,帮助分析每一次多空转换时,合理采取的投资策略。...一只期货合约分时图,均价线(黄色)和分时线占了大部分,想要听懂投机...
  • 思路:求一个二元函数在圆弧上的极值,加上端点的值,一起取个最小就是答案。 注意:1+λ为0时,P点在圆心,最短距离自然是半径。 求的极值点在圆的优弧或是劣弧的判断可以将直角坐标系转为极坐标,用...
  • # 当求圆弧的正逆时,可以根据圆弧上的三个与圆心构成的三个向量的行列式的正负来判断, # 如果行列式的值大于0,是逆时针,小于零,是顺时针,等于零,则一条直线上 # 这个a是圆弧的起点和...
  • 就是……判断p与圆心的连线与圆的交点在不在圆弧上,在就是它到p的距离,不在就是p跟端点的最短距离 #include #include #include #include #include #include #include #include #include #include using ...
  • 设输入三点为圆弧上的三个 ,) ,,三点按顺时针或者逆时针在圆弧上排列。 一、三点圆弧 1、判断三点是否共线及圆弧走向 求与的向量积   (1) 结果为正:圆弧是逆时针画   (2) 结果为负:圆弧是顺时针...
  • 由于需求,我需要动态的界面随意的下三个绘制一段圆弧,可是绘制圆弧的方向可不太好控制,我尝试着自己写条件去控制绘图方向,可是没有一个是成功的,于是我网上找了一天,但是都没有找到解决方案。...
  • 直线的扫描转换中点Bresenham算法 算法说明 设直线斜率0~1之间且位于第一象限光标走步规则为每次x方向加1y方向根据误差项判断或加1或加0 直线的扫描转换中点Bresenham算法 误差项判别式构造 当前P下一个...
  • 已知一个圆,并给出圆一点,求该点在的切线 求三点所在平面的法线方向 判断一点是否在圆弧范围内 判断一点是否在矩形内部 判断一点是否在长方体、球体、圆柱体内部 网格绘制长方体、球体、胶囊体 这里,我们...
  •   OpenCV中,可以画圆、线、矩形、椭圆和多边形,但并不能画出虚线,现希望通过OpenCV已有的函数画出由或线组成的虚线。 cv::circle() // 画一个简单圆 cv::clipLine() // 判断一条直线是否给定的矩形内 cv:...
  • SGU 227

    2015-09-06 22:03:19
    题目大意:给出一些圆弧的左右...如何判断是否在圆弧上呢,我们可以在两个圆弧端点之间连接一条向量,这样就可以转化为判断这个点在这条向量的哪一边了,叉积判一下就行了。这题最坑的就是判重合,情况很多,坑爹啊。
  • 寄蒜几盒?

    2018-11-27 20:59:00
    这若干个点在圆圈按顺时针顺序分布。 如果可以的话输出"Yes"(不含引号) 不可以的话输出"No"(不含引号) 输入 第一行一个整数n,表示圆圈有n个点 第二行n个整数,分别表示第1个点与第2个点之间圆弧的长度、第2个点...
  • 让尽可能多的点在圆弧上, 这样其他部分就能向外更多的扩展2. 怎么确定一个单位圆, 如果知道在圆弧上的两个点A(x1, y1), B(x2, y2)就能唯一确定一个圆心O(x, y), 可以用向量旋转2.1 可求出向...
  • POJ - 1266 -

    2017-11-16 21:04:00
    首先求出三个所在圆的圆心,也就是三角形的外心,然后判断着个圆上最上,最下,最左,最右四个是否圆弧上,如果,那么所求矩形的最上,最下,最左,最右边的坐标就是对应的的坐标,否则,应该有圆弧两端...
  • 这若干个点在圆圈按顺时针顺序分布。 如果可以的话输出"Yes"(不含引号) 不可以的话输出"No"(不含引号) 输入 第一行一个整数n,表示圆圈有n个点 第二行n个整数,分别表示第1个点与第2个点...
  • 这若干个点在圆圈按顺时针顺序分布。 如果可以的话输出"Yes"(不含引号) 不可以的话输出"No"(不含引号) 输入 第一行一个整数n,表示圆圈有n个点 第二行n个整数,分别表示第1个点与第2个点之间圆弧的...
  • 一条直线。输入的横坐标。 输入中相邻两间有半圆弧。(输入时不按坐标大小而是坐标乱序) 判断间构成的半圆弧是否相交。 假设n个点中 x1 和 x2之间有半圆弧,x3 和 x4 之间有半圆弧。 则当满足 ...
  • URAL 1043 三角形外接圆

    2013-09-27 20:48:27
    题意:给出一个圆弧上的三个,求出一个边平行于坐标轴面积最小的矩形并且这个矩形可以给这个圆弧覆盖掉,求矩形面积。 步骤: 1.先求出给出三点围城三角形的外接圆,圆弧就是这个圆的一部分。 2.找出外接圆的上下...

空空如也

空空如也

1 2 3 4
收藏数 67
精华内容 26
关键字:

判断点在圆弧上