图论----同构图(详解)
时间:2022-05-07
本文章向大家介绍图论----同构图(详解),主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
图论当中的术语,假设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 ,判断两次组成的图形是否是同构图。
思路之一:通过并查集确定环数/链数,和环内/链内的人数,再排序进行比较。
排序时按照人数排序,若人数相同要按照状态排序。注意这几点或许会比较容易过。
请先自己进行尝试,尝试后再参考代码。
1 #include<iostream>
2 #include<cstring>
3 #include<cstdio>
4 #include<math.h>
5 #include<vector>
6 #include<algorithm>
7 #include<queue>
8 #include<set>
9 using namespace std;
10 int pre[10100];
11 struct e{
12 int a,b;
13 };
14 e s1[10010];
15 e s2[10010];
16 int find(int x)
17 {
18 while(x!=pre[x])
19 x=pre[x];
20 return x;
21 }
22 int cmp(e a,e b){
23 if(a.a==b.a) return a.b>b.b;
24 else return a.a>b.a;
25 }
26 void init(int n)
27 {
28 for(int i=1;i<=n;i++)
29 pre[i]=i;
30 }
31 int main()
32 {
33 int t,cas=1;;
34 scanf("%d",&t);
35 while(t--)
36 {
37 for(int i=1;i<10010;i++)
38 {
39 s1[i].a=1;s1[i].b=0;
40 s2[i].a=1;s2[i].b=0;//最开始每个都是独立的,默认为链
41 }
42 bool flag=false;
43 int n1,m1,n2,m2;
44
45 scanf("%d%d",&n1,&m1);
46 init(n1);
47 for(int i=0;i<m1;i++)
48 {
49 int a,b;
50 scanf("%d%d",&a,&b);
51 int dx=find(a);
52 int dy=find(b);
53 if(dx!=dy)
54 {
55 pre[dx]=dy;
56 s1[dy].a+=s1[dx].a;
57 s1[dx].a=0;//把拉手的孩子数量加起来,下同
58 }
59 else s1[dy].b=1;//成环
60 }
61
62 scanf("%d%d",&n2,&m2);
63 init(n2);
64 for(int i=0;i<m2;i++)
65 {
66 int a,b;
67 scanf("%d%d",&a,&b);
68 int dx=find(a);
69 int dy=find(b);
70 if(dx!=dy)
71 {
72 pre[dx]=dy;
73 s2[dy].a+=s2[dx].a;
74 s2[dx].a=0;
75 }
76 else s2[dy].b=1;
77 }
78 if(n1==n2){
79
80 sort(s1+1,s1+n1+1,cmp);
81 sort(s2+1,s2+n2+1,cmp);//排序,若孩子的数量相同则对是否是环进行排序,这里要注意
82
83 for(int i=0;i<n1;i++)
84 if(s1[i].a!=s2[i].a||s1[i].b!=s2[i].b) {//判断数量,状态
85 flag=true;
86 break;
87 }
88 }
89 if(n1!=n2) flag=true;
90
91 if(flag) printf("Case #%d: NOn",cas++);
92 else printf("Case #%d: YESn",cas++);
93 }
94 return 0;
95 }
- JSP第三篇【JavaBean的介绍、JSP的行为--JavaBean】
- Java基础-06.总结二维数组,面向对象
- 04 整合IDEA+Maven+SSM框架的高并发的商品秒杀项目之高并发优化
- 过滤器第一篇【介绍、入门、简单应用】
- 通过pl/sql来格式化sql(r4笔记第63天)
- 程序员如何写出杀手级的简历
- 过滤器第二篇【编码、敏感词、压缩、转义过滤器】
- JSP第二篇【内置对象的介绍、4种属性范围、应用场景】
- Struts2的配置和一个简单的例子
- 监听器第一篇【基本概念、Servlet各个监听器】
- 监听器第二篇【统计网站人数、自定义session扫描器、踢人小案例】
- 通俗易懂的分析如何用Python实现一只小爬虫,爬取拉勾网的职位信息
- JSP第一篇【JSP介绍、工作原理、生命周期、语法、指令、行为】
- 一条执行时间两天半的sql语句简化(r4笔记第62天)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- linux nslookup命令使用详解
- Go 数据存储篇(五):建立数据库连接并进行增删改查操作
- Laravel 路由使用入门
- Go 数据存储篇(六):数据表之间的关联关系和关联查询
- 搭建nextcloud私有云存储网盘的教程详解
- Laravel 路由使用进阶
- 使用dig/nslookup命令查看dns解析的方法步骤
- Go 数据存储篇(七):GORM 使用入门
- 在 Linux 上使用 Multitail命令的教程
- 深入理解linux执行文件提示No such file or directory的背后原因
- Laravel 控制器:从 MVC 模式聊起
- 基于yolo5工地安全帽和禁入危险区域识别系统,附数据集
- Go 常见并发模式实现(一):调度后台处理任务的作业程序
- 路由使用进阶(二)
- linux No space left on device由索引节点(inode)爆满引发500问题