現在javaの学習を行っております。
5点の最短閉路を再帰を用いて求めるプログラムを作りたいです。
今、5点のすべての並び方を調べて、すべての経路の長さを図ることで
最短閉路を求めたいと覆っています。
そこで、0,1,2,3,4の数字の並べ方をすべて導出するプログラムを教えてください。
また、ほかによい考え方があればぜひ教えてください。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答5件
0
もっと良い方法があるかも知れませんが、一例を紹介します。
すべての並び替えた組み合わせを実現するにはpermutationという操作を行います。他の言語では標準関数になっていることもある操作です。
Javaの場合、permutationするのに標準ライブラリーだけではたぶん難しいと思いますので、Uncommons Mathsというライブラリーを使います。
Uncommons Mathsを使う場合、Mavenなら下記の依存関係を追加します。Mavenを使わない場合は、上記ページからライブラリーをダウンロードしてください。
lang
1 <dependency> 2 <groupId>org.uncommons.maths</groupId> 3 <artifactId>uncommons-maths</artifactId> 4 <version>1.2.2</version> 5 </dependency> 6 <dependency> 7 <groupId>jfree</groupId> 8 <artifactId>jfreechart</artifactId> 9 <version>1.0.13</version> 10 </dependency>
5個だとここでは結果が多すぎるので、数字4個の例を示します。
lang
1// import java.util.Arrays; 2// import java.util.List; 3// import org.uncommons.maths.combinatorics.PermutationGenerator; 4 5PermutationGenerator<Integer> gen = new PermutationGenerator<>(Arrays.asList(0, 1, 2, 3)); 6while (gen.hasMore()) { 7 List<Integer> a = gen.nextPermutationAsList(); 8 System.out.println(a); 9}
実行結果。
[0, 1, 2, 3] [0, 1, 3, 2] [0, 2, 1, 3] [0, 2, 3, 1] [0, 3, 1, 2] [0, 3, 2, 1] [1, 0, 2, 3] [1, 0, 3, 2] [1, 2, 0, 3] [1, 2, 3, 0] [1, 3, 0, 2] [1, 3, 2, 0] [2, 0, 1, 3] [2, 0, 3, 1] [2, 1, 0, 3] [2, 1, 3, 0] [2, 3, 0, 1] [2, 3, 1, 0] [3, 0, 1, 2] [3, 0, 2, 1] [3, 1, 0, 2] [3, 1, 2, 0] [3, 2, 0, 1] [3, 2, 1, 0]
投稿2015/06/12 06:35
総合スコア9390
0
ベストアンサー
こんにちは。
お手本になるようなアルゴリズムや、それを実装したコードがきっと
あるのだろうなと思いつつ、自分の頭の体操としてやってみました。
基本的な考え方は以下です。
0 以上 n以下の(n+1)個の整数を要素とする順列 p(n+1) は、
0 以上 (n-1)以下の n個の整数を要素とするある順列 p(n)に、
要素 n を追加して作成する。
その際に、要素 n を追加する場所は、以下の(n+1)ヶ所ある。
・p(n)の先頭
・p(n)の要素と要素の間(これは、(n-1)ヶ所ある。)
・p(n)の末尾
たとえば、0以上2以下を要素として持つ、[0,1,2]という順列に
要素 3 を加える位置は、先頭、0と1の間、1と2の間、末尾の
4カ所あり、これらの追加する位置の違いによって4つの順列、
[3,0,1,2]
[0,3,1,2]
[0,1,3,2]
[0,1,2,3]
が作成されます。この考え方で再帰のアルゴリズムを作成しました。
以下のソースで、
private static List<List<Integer>> getPermutations(Integer n)
が再帰で解のリストを求めるメソッドです。
lang
1import java.util.ArrayList; 2import java.util.Arrays; 3import java.util.List; 4 5public class Q11179 { 6 7 public static void main(String[] args) { 8 9 // 0以上4以下の整数のすべての順列のリストを作成 10 List<List<Integer>> list = getPermutations(4); 11 12 // 結果の表示(逆順にリスト要素を出力) 13 int counter = 0; 14 for (int i = list.size() - 1; i >= 0; --i) { 15 counter++; 16 System.out.println(counter + ":" + list.get(i)); 17 } 18 } 19 20 /* 21 * 0以上 n以下の整数を要素とする順列(を表現したリスト)を 22 * 要素として持つリストを作成 23 */ 24 private static List<List<Integer>> getPermutations(Integer n) { 25 26 // n が不正な値のとき、何もせず null を返して終了 27 if (n == null || n < 0) 28 return null; 29 30 // このメソッドの返り値となるリストを作成 31 List<List<Integer>> results = new ArrayList<List<Integer>>(); 32 33 // n = 0 の場合、要素の追加が可能なリスト[0]を要素とするリストを返す。 34 if (n == 0) { 35 results.add(new ArrayList<Integer>(Arrays.asList(0))); 36 return results; 37 } 38 39 // n > 0 の場合、まず、(n-1)に対する解のリストを再帰で取得 40 List<List<Integer>> prevResults = getPermutations(n - 1); 41 42 // (n-1)のときのリストをループし、要素の順列に n を加えた順列を作成 43 for (List<Integer> permutation : prevResults) { 44 for (int i = 0; i <= n; ++i) { // n を加える位置についてのループ 45 permutation.add(i, n); 46 results.add(new ArrayList<Integer>(permutation)); 47 permutation.remove(n); 48 } 49 permutation.clear(); // 全要素を削除しておく 50 } 51 prevResults.clear(); // 全要素を削除しておく 52 53 return results; 54 } 55}
上記を実行すると、以下のような出力が得られます。
行頭の数字は、組み合わせの数を数えるためのものです。
lang
11:[0, 1, 2, 3, 4] 22:[0, 1, 2, 4, 3] 33:[0, 1, 4, 2, 3] 44:[0, 4, 1, 2, 3] 55:[4, 0, 1, 2, 3] 6・・・ 7117:[3, 2, 1, 4, 0] 8118:[3, 2, 4, 1, 0] 9119:[3, 4, 2, 1, 0] 10120:[4, 3, 2, 1, 0]
5個の要素による順列の数は、公式nPr = n!/(n-r)! に n=r=5 を代入して
5P5 = 5!/(5-5)! = (54321)/0! = 120/1 = 120
ですので、出力例の行数は合っています。
また、ソースコードのmainメソッドの中で
List<List<Integer>> list = getPermutations(4);
としているところを
List<List<Integer>> list = getPermutations(5);
にしたり、
List<List<Integer>> list = getPermutations(0);
にしたりしてみましたが問題なく動くのを確認しました。
ただし私の手元のPCでは、
getPermutations(8);
まではいけましたが
getPermutations(9);
でヒープを使い果たして
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
となりました。
以上、ご参考になれば幸いです。
投稿2015/06/12 06:54
編集2015/06/14 21:35総合スコア9058
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
こんなんいかがでしょう
lang
1package a; 2 3public class TT11179 { 4 public static void main(String[] args) { 5 try { 6 new Permutation() { 7 @Override 8 public void found(int[] list) { 9 for(int val : list) { 10 System.out.print(" " + val); 11 } 12 System.out.println(""); 13 } 14 } 15 .find(5); 16 } 17 catch(Throwable e) { 18 e.printStackTrace(); 19 } 20 } 21 22 public static abstract class Permutation { 23 private int _count; 24 private boolean[] _picked; 25 private int[] _list; 26 27 public void find(int count) { 28 _count = count; 29 _picked = new boolean[count]; 30 _list = new int[count]; 31 pick(0); 32 } 33 34 private void pick(int index) { 35 if(_count <= index) { 36 found(_list); 37 return; 38 } 39 for(int val = 0; val < _count; val++) { 40 if(_picked[val] == false) { 41 _picked[val] = true; 42 _list[index] = val; 43 pick(index + 1); 44 _picked[val] = false; 45 } 46 } 47 } 48 49 public abstract void found(int[] order); 50 } 51}
投稿2015/06/15 21:52
総合スコア159
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
順列を求める方法はいくつもあります。
参考:
- リスト 8 : 順列の生成(再帰版) http://www.geocities.jp/m_hiroi/java/abcjava04.html
- 「6枚のカードの並べ方を求めて!」問題解説 #java https://codeiq.jp/magazine/2014/05/10469/
投稿2015/06/12 23:36
総合スコア22324
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2015/06/15 08:08