• 图论----同构图


    图论其中的术语。假设G=(V,E)和G1=(V1,E1)是两个图,假设存在一个双射m:V→V1,使得对全部的x,y∈V均有xy∈E等价于m(x)m(y)∈E1,则称G和G1是同构的,这种一个映射m称之为一个同构。假设G=G1。则称他为一个自同构。


    简单来说,同构图的结点数必须同样。结构必须同样。

    如图3.6,第一个图形和第二个图形的差别在于环的数量。第一个图形为一个环。第二个为两个环,所以不是同构图。

    若删去z1和u1,删去v1和w1,连接z1和w1。成为一个v1u1的链和z1w1x1y1的环,依然不是同构图。由于必须环数同样,链数同样。

    但这还是缺少一个条件,比方图形A存在两个环a1和a2,a1有3个结点,a2有5个结点,图形B也有两个环,b1有4个结点,b2有4个结点。依然不是同构图,这里的条件就是环上或链上的借点数同样,和结点顺序无关。


    引入例题,HDU3926-Hand in Hand ,推断两次组成的图形是否是同构图。

    思路之中的一个:通过并查集确定环数/链数,和环内/链内的人数。再排序进行比較。

    排序时依照人数排序,若人数同样要依照状态排序。注意这几点也许会比較easy过。

    请先自己进行尝试。尝试后再參考代码。


    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<math.h>
    #include<vector>
    #include<algorithm>
    #include<queue>
    #include<set>
    using namespace std;
    int pre[10100];
    struct e{
        int a,b;
    };
    e s1[10010];
    e s2[10010];
    int find(int x)
    {
        while(x!=pre[x])
            x=pre[x];
        return x;
    }
    int cmp(e a,e b){
        if(a.a==b.a) return a.b>b.b;
        else return a.a>b.a;
    }
    void init(int n)
    {
        for(int i=1;i<=n;i++)
            pre[i]=i;
    }
    int main()
    {
        int t,cas=1;;
        scanf("%d",&t);
        while(t--)
        {
            for(int i=1;i<10010;i++)
            {
                s1[i].a=1;s1[i].b=0;
                s2[i].a=1;s2[i].b=0;//最開始每一个都是独立的,默觉得链
            }
            bool flag=false;
            int n1,m1,n2,m2;
    
            scanf("%d%d",&n1,&m1);
            init(n1);
            for(int i=0;i<m1;i++)
            {
                int a,b;
                scanf("%d%d",&a,&b);
                int dx=find(a);
                int dy=find(b);
                if(dx!=dy)
                {
                    pre[dx]=dy;
                    s1[dy].a+=s1[dx].a;
                    s1[dx].a=0;//把拉手的孩子数量加起来,下同
                }
                else s1[dy].b=1;//成环
            }
    
            scanf("%d%d",&n2,&m2);
            init(n2);
            for(int i=0;i<m2;i++)
            {
                int a,b;
                scanf("%d%d",&a,&b);
                int dx=find(a);
                int dy=find(b);
                if(dx!=dy)
                {
                    pre[dx]=dy;
                    s2[dy].a+=s2[dx].a;
                    s2[dx].a=0;
                }
                else s2[dy].b=1;
            }
            if(n1==n2){
    
            sort(s1+1,s1+n1+1,cmp);
            sort(s2+1,s2+n2+1,cmp);//排序,若孩子的数量同样则对是否是环进行排序。这里要注意
    
                for(int i=0;i<n1;i++)
                if(s1[i].a!=s2[i].a||s1[i].b!=s2[i].b) {//推断数量,状态
                    flag=true;
                    break;
                }
            }
            if(n1!=n2)    flag=true;
    
            if(flag) printf("Case #%d: NO
    ",cas++);
            else printf("Case #%d: YES
    ",cas++);
        }
        return 0;
    }
    




  • 相关阅读:
    D. Time to Run【构造】
    P3388 割顶 【求割点个数】
    处女座的测验 素数,构造
    处女座与复读机 DP
    求一个分数小数点后指定位数的数字
    安卓开发创建活动,布局,添加按钮,she使用Toast,设菜单,使菜单相关联等操作
    三进制 处女座的砝码 高精度
    上海高校程序设计联赛 D-CSL的字符串 栈模拟
    区间DP经典 石子合并
    区间DP 洛谷P2858牛奶零食
  • 原文地址:https://www.cnblogs.com/tlnshuju/p/6879332.html
Copyright © 2020-2023  润新知