質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.49%
アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

3回答

2050閲覧

pythonで完全グラフの判別を作っています。

Isemoca

総合スコア10

アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2018/12/11 10:08

編集2018/12/11 11:20

###pythonで完全グラフの判別を作っています。

頂点1と頂点2を結ぶ枝を”(頂点1、頂点2)”と表現し、それが複数存在する時の完全グラフの要素を表示したいです。


(0,1)、(0,3)、(0,4)、(1,3)、(1,4)、(2,4)、(3,4)という要素がある時、その中に存在する部分的な複数の完全グラフ(0,1,3,4)(2,4)という結果が出て欲しいです。

イメージ説明
うまく説明できないのでイメージをのせました。
二つの赤丸のように分けたいです。

要素の多い部分完全グラフ(0,1,3,4)に完全に含まれる部分完全グラフ(0,1,3)や(0,4)などは除外しています。

この質問の意図は 0や1が文書を意味しており、文書間の類似度を出し、設定した閾値より高い文書の組み合わせを(0,1)のように表現しています。目標は類似度の高い文書を一つにまとめることで、そのためにこの方法をとりました。

わかりにくい質問ですみません、何かありました追記します。

該当のソースコード

python3

1list = [(0,1),(0,3),(0,4),(1,3),(1,4),(2,4),(3,4)]

試したこと

全投げになってしまって申し訳ないです。考えてはみたんですがアルゴリズムが思いつかないです

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tiitoi

2018/12/11 10:17 編集

与えられたグラフが完全グラフかどうか判別したいということであればわかりますが、期待する結果が (0,1,3,4)(2,4) というのはどういうことでしょうか?この (0,1,3,4)(2,4) はなにを意味していますか?
Isemoca

2018/12/11 10:28

追記しました。分からなければ質問ください
tiitoi

2018/12/11 10:36 編集

あるグラフの"完全グラフである"部分グラフを列挙するということであれば、(0, 1, 3), (0, 1, 4), (1, 4), ... のように他にも完全グラフを構成する部分グラフはあると思いますが、どういった規則でその2つだけ選ばれたのでしょうか?
Isemoca

2018/12/11 10:49

要素の多い部分完全グラフ(0,1,3,4)に完全に含まれる部分完全グラフ(0,1,3)や(0,4)などは除外しています。
Isemoca

2018/12/11 10:56 編集

この質問の意図は 0や1が文書を意味しており、文書間の類似度を出し、設定した閾値より高い文書の組み合わせを(0,1)のように表現しています。目標は類似度の高い文書を一つにまとめることで、そのためにこの方法をとりました。
guest

回答3

0

tiitoiさんの回答からnetworkxを使えばうまくいくと思い、試したところうまくいきそうです。

python

1import networkx as nx 2G = nx.Graph() 3edgelist=[(0,1),(0,3),(0,4),(1,3),(1,4),(2,4),(3,4)] 4G.add_edges_from(edgelist) 5 6for i in nx.find_cliques(G): 7 print(i) 8 9# [4, 0, 1, 3] 10# [4, 2] 11

ちなみにグラフを描画する場合は、nx.draw_networkx(G)を実行すると、質問に記載されるものと同じトポロジーのグラフが表示されます。

投稿2018/12/11 15:26

R.Shigemori

総合スコア3376

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

質問の内容をグラフ理論の用語で定義すると、

「あるグラフ G が与えられたとき、極大であるクリークを求める」**極大クリーク問題 (maximal clique problem)**ということになります。

  • クリーク (clique): グラフ G の部分グラフのうち、完全グラフであるもの
  • 極大 (maximum) である部分グラフ: 部分グラフのうち、他の部分グラフに含まれないもの

極大クリーク列挙のアルゴリズムとしては、「Bron-Kerbosch アルゴリズム」があるようです。

In computer science, the Bron–Kerbosch algorithm is an algorithm for finding maximal cliques in an undirected graph.

検索ワードとしては、「極大クリーク」「maximum cliques」で調べるとよいです。
上記以外にも いくつかのアルゴリズム があるようです。

GitHub とかで探せば実装例があるかもしれません。

投稿2018/12/11 11:27

編集2018/12/11 11:28
tiitoi

総合スコア21956

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ご自身でおっしゃっているとおりこの質問は「丸投げ」です。多少なりともご自分で考えた論理の断片を書けば丸投げにはならなかっただろうと思いますが・・・

実際にこういう論理が必要となって「どう実現しよう」というのが質問者さんの課題ならば「それについてのアルゴリズムを参照したり、それをやってくれるライブラリーを探す」というのが最も簡単に答えにたどり着ける方法だろうと思います。それについては既に回答がついているので、「それを実現するアルゴリズムを自分で考えてみる」というアプローチについて若干コメントしてみます。

まず問題を小さな問題に分割する

「グラフの中から最大クリークを全て列挙する」というのをいきなり考えても歯が立たないだろうと思います。大抵の問題で言えることですが「それを実現するための補題を設定しそれを考える」というふうに段階的に料理していきましょう。本件でいえば

(A) グラフの中から最大クリークを全て列挙する」
=> (B1) グラフの中から特定の辺を含む最大クリークを求める
==> (C1) グラフの中にあるクリークがあったとして、それに含まれないノードを追加したときそれが完全グラフ(クリーク)となっているかどうか検査する
===> (D1) クリークを成すノード群とそこに含まれないあるノードが互いに接続されているかどうか検査する
====> (E1) あるノードが別のノードと隣接しているか検査する
=> (B2) グラフの中から特定のクリークを構成する辺を除く
・・・

このように段階的により小さくてより単純な補題に分解しながら考えていくのが一つのコツです。(A)をやるためには(B)がわかればよい、(B)をやるためには(C)がわかればよい・・・という感じですね。

アルゴリズムを言語機能を使って実装する

アルゴリズムを考えるときは大抵特定の言語とは関係ない抽象的な論理として考えます。それをコードに落とす際に具体的な言語、例えばPythonが持っている機能をどう応用すればよいかを考えることになります。例えば(E)ですけど

コード1

Python

1edges = [(0, 1), (0, 2)] 2 3def is_connected(node0, node1): 4 for edge in edges: 5 if edge[0] == node0 and edge[1] == node1: 6 return True 7 if edge[1] == node0 and edge[0] == node1: 8 return True 9 return False

などとすればできそうです。しかしPythonに慣れてくると「こんな長ったらしいコードは必要ない」ということがだんだんわかってきます。

コード2

Python

1edges = [(0, 1), (0, 2)] 2 3# edgesの中の辺は必ずノード番号の昇順のtupleになっていると仮定 4def is_connected(node0, node1): 5 edge = (node0, node1) if node0 < node1 else (node1, node0) 6 return edge in edges

tupleはhashableなのでtupleの列(例えばlist)から特定のtupleが含まれるかどうかはin一発でよいというPythonの知識があればこういうふうに書けます。
さらに型の特徴の理解が深まればinはlistに対して探すよりsetに対して探す方が桁違いに早いということもわかってきます。(言語の特徴というよりlistは順番に要素を並べただけ、setは要素を高速に見つけられるようにhashアルゴリズムを使っているものというような一般アルゴリズムの知識がベースになるといった方がよいかも知れません)

コード3

Python

1edges = {(0, 1), (0, 2)} # こう書くとsetになる 2 3# edgesの中の辺は必ずノード番号の昇順のtupleになっていると仮定 4def is_connected(node0, node1): 5 edge = (node0, node1) if node0 < node1 else (node1, node0) 6 return edge in edges

コードの行数自体はコード2もコード3も同じですが、辺の数が1000, 10000, 100000と増えていくとコード3の方がとてつもなく早いので「listとsetならsetを使うべき」という選択ができることは割と重要です。


さて他者が考えた論理、例えばアルゴリズムの解説などを読むことはかなりよい訓練になると思います。それは本回答に書いた「小さな問題に分割する」や「特定の言語機能をうまく使ってわかりやすく簡潔に論理を記述する」というお手本を自分の頭の中の引き出しに蓄える機会になるからです。ただし「ただ漠然と見ているだけ」では引き出しに知識が増えていきません。自分なりに考える(咀嚼する)というプロセスを大事にしてください。典型的には「その論理はどういうアプローチからきたものかを考える」「自分で整理して実際にコードを書いて期待どおりに動くかデバッグする」という繰り返しが大事です。そうしないと力がつきませんし力がついていかないと応用(アプリケーション)が書けるようになりません。

また最初にコメントしたように「質問するなら自分がどこまで考えたのか」を書くべきです。丸投げ質問ばかりしていると(初心者かどうかとは別の次元で)閲覧者にそっぽを向かれかねませんのでご注意を。

投稿2018/12/12 05:15

KSwordOfHaste

総合スコア18394

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.49%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問