2部グラフのjudge関数
このワークシートはMath by Codeの一部です。
質問:Gの各頂点をvとするとGの辺の総数2|E(G)|=Σdeg(v)はどうして言えるでしょうか。
<握手補題>
上記の内容は握手補題と呼ばれたりしてるね。当たり前すぎて説明がしにくいかもしれません。
1辺{u,v}は、辺1つを2頂点u,vのどちらからでも重複して数えられる。
これがどの辺についても言える。
だから、辺数の合計の2倍は重複を込めた点の総数と等しい。
重複をこめた点の総数は頂点の次数の合計で求めることができる。
1.完全2部グラフ
グラフG=(V,E)の頂点Vをn個の集合に分割してみる。
たとえば、2つの集合、部VAと部VBに分けたとしよう。
部VAのどの2点x,yを選んでも辺{x,y}はEにはなく、
部VBのどの2点x,yを選んでも辺{x,y}はEにはない。
言い換えるとGのどの辺も2つの部にまたがっていて、1つの部に属するものがない。
このとき、2部グラフはG=(VA,VB,E)とかける。
一般に、Gがn部グラフだということは、隣接辺を持たない点集合Viのn個(V1,....,Vn)に頂点分割ができるということだから、Gのつながり具合を特徴づけていると言えるね。G=(V1,....,Vn,E)とかける。
とくに、n個の点集合からどの2つの部X,Yを選んでも、部のどの2点x∈X, y∈Yでも隣接しているなら、Gは完全n部グラフと呼ばれる。|Vi|=piのとき、各部の頂点数を並べて、G=K(1,2,3)とか、K1,2,3などと表示することがあるね。
質問:要素数p*qの完全2部グラフKp,qを作るにはどうしたらよいでしょうか。
頂点p個の集合Aとq個の集合Bを用意し、Aの各点に対してBの全点を結ぶ辺を作ります。
頂点と辺をGに加えたものが完全2部グラフG(A,B,E)=K(p,q)です。
つまり、AとBの集合の直積が辺集合になるね。
同じ部にある頂点は隣接してないので、部という言葉がピンとこないかもしれない。
補グラフを意識してみよう。
2部グラフの補グラフでは、同じ部にある頂点はどれもつながるので完全グラフになるね。
#[IN]Python
#========================================================
#完全2部グラフKp,qを色分けして
import networkx as nx
import itertools
import matplotlib.pyplot as plt
def K(p,q,pos_num):
Vp = list(range(1,1+p)) #第1部の頂点は1からpまでのp個
Vq = list(range(p+1,p+1+q)) #第2部の頂点はp+1からp+qまでのq個
E = list(itertools.product(Vp,Vq)) #VpとVqの直積のリスト
G = nx.Graph()
V=Vp+Vq
colorList = ['Red']*p + ['Green']*q #色名は頭文字を大文字にする
G.add_nodes_from(V)
G.add_edges_from(E)
plt.subplot(2,2,pos_num)
nx.draw_networkx(G,node_color=colorList)
K(3,1,1)
K(3,2,2)
K(3,3,3)
K(3,4,4)
#========================================================
[OUT]
完全2部グラフの色分け
<不完全な2部グラフ>
完全な2部グラフは直積の発想を使ってつくることができた。
完全でない場合は、2部に頂点をわけておき、
部間を結ぶ辺をあとで追加すればよいね。
2部用のパッケージを使ってみよう。やっていることは素朴だ。
色はグラフそのものの構造データではないからdrawするときに部ごとに指定しよう。
#[IN]Python
#============================================================
import networkx as nx
from matplotlib import pyplot as plt
from networkx.algorithms import bipartite
B = nx.Graph() #部のフラグbipartiteに0,1を立てておこう。
B.add_nodes_from([1, 2, 3, 4], bipartite=0)
B.add_nodes_from(["a", "b", "c"], bipartite=1)
B.add_edges_from([(1, "a"), (1, "b"), (2, "b"), (2, "c"), (3, "c"), (4, "a")]) #部間の連結辺
colorList = ['Red']*4 + ['Green']*3 #色名は頭文字を大文字にする #色分け
nx.draw_networkx(B,node_color=colorList)
#============================================================
[OUT]
2部グラフの1例
2.2部グラフの判定
完全2部グラフを作るのは、直積を使えば簡単でしたね。
質問:頂点が4か6のグラフが2部グラフか完全2部グラフかを判定するにはどうしたらよいでしょう。
完全2部グラフなら、頂点数は2つの部の頂点数の積になる。
<頂点4の場合>
完全2部グラフなら4=2+2 4=2*2から、辺が4本だとK2,2の可能性がある。
4つの頂点を2組にわけて、どちらも部の中に結ぶ辺がないと2部グラフと判断するのがjudge4(G)関数だ。
2部グラフの頂点の2集合VA,VB、辺集合Eから2部グラフを色分けする関数がmakebipatiteだ。
judge4の中に、この描画関数を使うと2部グラフの確認が目で見てわかる。
#[IN]Python
#====================================================================
import networkx as nx
from matplotlib import pyplot as plt
import itertools
from networkx.algorithms import bipartite
pos_num=1
def makebipatite(VA,VB,E):
B = nx.Graph()
B.add_nodes_from(VA, bipartite=0)
B.add_nodes_from(VB, bipartite=1)
B.add_edges_from(E)
colorList = ['Red']*len(VA) + ['Green']*len(VB) #色名は頭文字を大文字にする
nx.draw_networkx(B,node_color=colorList)
def judge4(G):
global pos_num
V=G.nodes()
E=G.edges()
V1=list(itertools.combinations(V,2))
for Pset in V1:
p,q = Pset[0],Pset[1]
R = list(set(V)-set([p,q]))
r,s= R[0],R[1]
# もし2️部グラフと判断されたら、makebipatite関数で描画する。
if not((p,q) in E or (q,p) in E or (r,s) in E or (s,r) in E):
VA= [p,q]
VB= R
E= E
plt.subplot(2,2,pos_num)
makebipatite(VA,VB,E)
pos_num +=1
return True
return False
V=[1,2,3,4]
E1=[(1,2),(2,3),(3,4),(4,1)] #四角形と4頂点
E2=[(1,2),(3,4)] #4頂点と2つの辺
G1=nx.Graph()
G1.add_nodes_from(V)
G1.add_edges_from(E1)
G2=nx.Graph()
G2.add_edges_from(E2)
G2.add_nodes_from(V)
judge4(G1)
judge4(G2)
#====================================================================
[OUT]
4点の2部グラフ
・頂点6の場合
辺数が7のグラフGがあるとする。
6=3+3, 3*3=9, 9-7=2から、2本の辺の追加で完全グラフK3,3に直せるかもしれない。
6=2+4, 2*4=8, 8-7=1から、1本の辺の追加で完全グラフK2,4に直せるかもしれない。
6=1+5, 1*5=5, 5-7<0から、完全グラフよりも辺が多いので2部グラフには直せない。
ということで、
2部グラフの頂点の2集合VA,VB、辺集合Eから2部グラフを色分けする関数がmakebipatiteは点数に
関係なく使える。judge6の中に、この描画関数を使うと2部グラフの確認が目で見てわかる。
judge6の作り方
6点から3点選び、3点が連結せず、残り3点も連結していないときか、
6点から2点選び、2点が連結せず、残り4点も連結しないとき。
このどちらかが言えれば2部グラフと判断するのがjudge6(G)関数だ。
#[IN]Python
#==================================================================
import networkx as nx
from matplotlib import pyplot as plt
import itertools
from networkx.algorithms import bipartite
pos_num=1
def makebipatite(VA,VB,E):
B = nx.Graph()
B.add_nodes_from(VA, bipartite=0)
B.add_nodes_from(VB, bipartite=1)
B.add_edges_from(E)
colorList = ['Red']*len(VA) + ['Green']*len(VB) #色名は頭文字を大文字にする
nx.draw_networkx(B,node_color=colorList)
def judge6(G):
global pos_num
V = G.nodes()
E = G.edges()
V1 = list(itertools.combinations(V,3))
for Pset in V1:
p,q,r = Pset[0],Pset[1],Pset[2]
R = list(set(V)-set([p,q,r]))
s,t,u = R[0],R[1],R[2]
# もし2️部グラフと判断されたら、makebipatite関数で描画する
siki1= (p,q) in E or (q,p) in E or (q,r) in E or (r,q) in E or (r,p) in E or (p,r) in E
siki2= (s,t) in E or (t,s) in E or (t,u) in E or (u,t) in E or (u,s) in E or (s,u) in E
if not(siki1 or siki2):
VA = [p,q,r]
VB = R
E = E
print(VA,VB,E)
plt.subplot(2,2,pos_num)
makebipatite(VA,VB,E)
pos_num +=1
V1 = list(itertools.combinations(V,2))
for Pset in V1:
p,q= Pset[0],Pset[1]
R = list(set(V)-set([p,q]))
r,s,t,u = R[0],R[1],R[2],R[3]
# もし2️部グラフと判断されたら、makebipatite関数で描画する
siki1= (p,q) in E or (q,p) in E
siki2= (r,s) in E or (r,t) in E or (r,u) in E or (s,r) in E or (s,t) in E or (s,u) in E
siki3= (t,r) in E or (t,s) in E or (t,u) in E or (u,r) in E or (u,s) in E or (u,t) in E
if not(siki1 or siki2 or siki3):
VA = [p,q]
VB = R
E = E
print(VA,VB,E)
plt.subplot(2,2,pos_num)
makebipatite(VA,VB,E)
pos_num +=1
V=[1,2,3,4,5,6]
E1=[(1,2),(2,3),(3,4),(4,5),(5,6),(6,1),(2,5)] #日の字型の6点
E2=[(1,5),(2,5),(3,5),(4,5),(1,6),(2,6),(3,6)] #1,2,3,4につなぐ5,6。
G1=nx.Graph()
G1.add_nodes_from(V)
G1.add_edges_from(E1)
judge6(G1)
G2=nx.Graph()
G2.add_nodes_from(V)
G2.add_edges_from(E2)
judge6(G2)
#==================================================================
[OUT]