圖論----同構圖(詳解)


圖論當中的術語,假設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: NO\n",cas++);  
92             else printf("Case #%d: YES\n",cas++);  
93         }  
94         return 0;  
95     }  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM