全列挙した組み合わせから特定の組み合わせを除去して、残りの組み合わせを全列挙する方法があれば教えていただきたいです。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/07/30 06:17
2020/07/30 07:31
2020/07/30 07:41
2020/07/30 07:48
2020/07/30 07:57
2020/07/30 08:03 編集
2020/08/02 02:38 編集
回答2件
0
ベストアンサー
質問例の組み合わせ数が変わるパターンだとその都度似た処理をコピーしなければならず効率が悪いので、一覧を作る部分から作り直しました。
ただビット演算を使う方が楽なためint配列をString文字列に置き換えて処理しています。
外部からint配列で引数が渡されるとかいう場合、String文字列に置き換える処理を入れて下さい。
支配関係の除外は現在の処理の場合、
高ランクから順番にしているため、必然的に下位ランクが後になるので、
新しく追加する物が既に一覧にある物の下位になるかどうかをチェックして
一覧に加えない方式で処理しています。
java
1import java.util.ArrayList; 2import java.util.Arrays; 3import java.util.List; 4import java.util.stream.IntStream; 5 6public class NNN { 7 8 static String projectA[] = { "1100", "1010", "0100" }; 9 static String projectB[] = { "1010", "0010", "0100" }; 10 static String projectC[] = { "0101", "0001", "1000" }; 11 12 static String projectALL[][] = { projectA, projectB, projectC }; 13 static String projectList[] = Arrays.stream(projectALL).flatMap(pl -> Arrays.stream(pl)).toArray(String[]::new); 14 15 static int rProjectBin = Integer.parseInt("1111", 2); 16 17 static String company[] = { "A社", "B社", "C社" }; 18 19 public static void main(String[] args) { 20 List<String> indexStrList = createIndexStrList(); 21 sysoutResult(indexStrList); 22 } 23 24 public static List<String> createIndexStrList() { 25 List<String> indexStrList = new ArrayList<>(); 26 for (int i = 0; i < projectList.length; i++) { 27 String result = setIndexStrList(indexStrList, projectList[i], String.valueOf(i), i + 1); 28 excludeDominance(indexStrList, result); 29 } 30 return indexStrList; 31 } 32 33 public static String setIndexStrList(List<String> indexStrList, String pProject, String indexStr, int idx) { 34 int pBin = Integer.parseInt(pProject, 2); 35 for (int i = idx; i < projectList.length; i++) { 36 int cBin = Integer.parseInt(projectList[i], 2); 37 // ビット演算xor 38 int rBin = pBin ^ cBin; 39 // ビット演算xorの結果にandで演算を行い、適用ビットと同じ値であれば適用された(0から1に変わった)ことになる 40 if ((rBin & cBin) == cBin) { 41 String addStr = indexStr + "," + i; 42 // 演算結果が"1111"と同じ場合、結果を返す 43 if (rBin == rProjectBin) { 44 return addStr; 45 } else { 46 // 演算結果が"1111"でない場合、再帰で自己メソッドを呼び出す 47 String result = setIndexStrList(indexStrList, Integer.toBinaryString(rBin), addStr, i); 48 excludeDominance(indexStrList, result); 49 } 50 } 51 } 52 return null; 53 } 54 55 public static void excludeDominance(List<String> indexStrList, String addIndexStr) { 56 // 支配関係にあるプロジェクトを除外する 57 if (addIndexStr == null) { 58 return; 59 } 60 if (indexStrList.isEmpty()) { 61 indexStrList.add(addIndexStr); 62 return; 63 } 64 String[] addIndexesStr = addIndexStr.split(","); 65 // 会社数以上プロジェクトがある場合、複数の同じ会社が指定されているので支配関係不明としてチェックしない 66 if (addIndexesStr.length > projectALL.length) { 67 indexStrList.add(addIndexStr); 68 return; 69 } 70 int[][] indexes = convertIndexesStr(addIndexesStr); 71 // プロジェクトで会社の重複がある場合、複数の同じ会社が指定されているので支配関係不明としてチェックしない 72 if (doubleCheck(indexes, -1)) { 73 indexStrList.add(addIndexStr); 74 return; 75 } 76 for (String listIndexStr : indexStrList) { 77 String[] listIndexesStr = listIndexStr.split(","); 78 int[][] listIndexes = convertIndexesStr(listIndexesStr); 79 // 会社の数が同じ場合 80 if (indexes.length == listIndexes.length) { 81 boolean[][] bolLen = new boolean[indexes.length][2]; 82 for (int i = 0; i < indexes.length; i++) { 83 // 会社が同じ場合 84 if (indexes[i][0] == listIndexes[i][0]) { 85 bolLen[i][0] = true; 86 } 87 // 加えようとしている会社のランクIndexが既に一覧にある会社のランクIndex以上(ランク下位)の場合 88 if (indexes[i][1] >= listIndexes[i][1]) { 89 bolLen[i][1] = true; 90 } 91 } 92 // 会社数によりチェック用の配列を作成 93 boolean[][] chkBol = IntStream.range(0, indexes.length) 94 .mapToObj(i -> new boolean[] {true, true}).toArray(boolean[][]::new); 95 // チェック結果が全てtrue(会社の組み合わせが同じで、ランク下位以下)の場合 96 if (Arrays.deepEquals(bolLen, chkBol)) { 97 // リストに加えず処理を終了(除外扱い) 98 return; 99 } 100 } 101 } 102 indexStrList.add(addIndexStr); 103 } 104 105 public static boolean dominanceCheck(List<String> indexStrList, String indexStr) { 106 // 支配関係のチェックを行う 107 String[] indexesStr = indexStr.split(","); 108 // 会社数以上プロジェクトがある場合、複数の同じ会社が指定されているので支配関係不明としてチェックしない 109 if (indexesStr.length > projectALL.length) { 110 indexStrList.add(indexStr); 111 return false; 112 } 113 int[][] indexes = convertIndexesStr(indexesStr); 114 // プロジェクトで会社の重複がある場合、複数の同じ会社が指定されているので支配関係不明としてチェックしない 115 if (doubleCheck(indexes, -1)) { 116 indexStrList.add(indexStr); 117 return false; 118 } 119 return true; 120 } 121 122 public static boolean doubleCheck(int[][] indexes, int argConpanyIdx) { 123 // 一社で複数のプロジェクトがあるかどうかチェックする 124 for (int[] indexe : indexes) { 125 int conpanyIdx = indexe[0]; 126 boolean result = conpanyIdx == argConpanyIdx; 127 if (!result) { 128 return result; 129 } 130 return doubleCheck(indexes, conpanyIdx); 131 } 132 return false; 133 } 134 135 public static int[][] convertIndexesStr(String[] indexesStr) { 136 // 会社名とランクをIndexに置き換え、会社が複数ある場合まとめる 137 int[][] indexes = new int[indexesStr.length][2]; 138 for (int i = 0; i < indexesStr.length; i++) { 139 String[] idxs = indexesStr[i].split(","); 140 for (String index : idxs) { 141 int projectSize = 0; 142 for (int j = 0; j < projectALL.length; j++) { 143 String[] projects = projectALL[j]; 144 for (int k = 0; k < projects.length; k++) { 145 if (Integer.parseInt(index) == projectSize + k) { 146 indexes[i] = new int[] {j, k}; 147 } 148 } 149 projectSize += projects.length; 150 } 151 } 152 } 153 return indexes; 154 } 155 156 private static void sysoutResult(List<String> indexStrList) { 157 // 結果をコンソールに出力する 158 for (String indexStr : indexStrList) { 159 System.out.println("-------------------------"); 160 String[] indexes = indexStr.split(","); 161 for (String index : indexes) { 162 int projectSize = 0; 163 for (int i = 0; i < projectALL.length; i++) { 164 String[] projects = projectALL[i]; 165 for (int j = 0; j < projects.length; j++) { 166 if (Integer.parseInt(index) == projectSize + j) { 167 System.out.println( 168 company[i] + "の" + (j + 1) + "位のプロジェクト=1"); 169 } 170 } 171 projectSize += projects.length; 172 } 173 } 174 } 175 } 176}
投稿2020/08/03 01:03
編集2020/08/03 01:08総合スコア2183
0
やりたいことは、以下の通りで実現できると思います
私が現状考えている方法としては下記です。
①配列を用意してそこに最初の解の順位を保存
②以降、既存の解と新規の解との順位を比較
----支配関係がある場合 ==>支配されている解を消去、新たな解を保存
----支配関係がない場合 ==>新たな解として保存
③保存されている解を出力
支配関係のチェックは、正直コメントのやりとり見てもあまりわからなかったので
サンプルをうまく修正してくれればと思います。
考え方だけ。
プロジェクトと順位を一意の文字列に変換します。
変換ルール
先頭1文字目は、成り立つプロジェクトの数
2文字目、Aプロジェクトの順位
3文字目、Bプロジェクトの順位
4文字目、Cプロジェクトの順位
※順位は1位:4点、2位:2点、3位:1点の合計
変換した文字列の各桁を見て、どちらか一方にのみ支配関係があれば、そのどちらか
なければないというのを表す関数を作ります。
※ここの評価方法がよくわからないので、直してください。
先頭1文字が一致しない場合、どちらも支配関係にない。
2文字目以降
第一引数(left)が大きい場合、isLeftをtrueに、第二引数が大きい場合、isRightをtrueに
最終的にどちらか”だけ”フラグがたっていたら、そのフラグに準じた値を返却
java
1/* 2 * PRJ評価文字列を作成 3 * 各PRJの評価をABCの順に連結した文字列を返す。 4 */ 5private static String toHyoukaStr(int... prjs) { 6 int[] company = { 0, 0, 0 }; // {A社, B社, C社} 7 int[] rank = { 4, 2, 1 }; // 順位の重みづけ 2位、3位の合計より1位を大きく 8 9 for (int i = 0; i < prjs.length; i++) { 10 company[prjs[i] / 3] += rank[prjs[i] % 3]; 11 } 12 13 // int配列を文字列に変換{1,2,3} -> "123" 14 String ret = "" + prjs.length + java.util.Arrays.stream(company).mapToObj(Integer::toString).collect(Collectors.joining()); 15 return ret; 16} 17 18/* 19 * 支配されているかのチェック. 20 * 21 * @left 評価するprj順位文字列 22 * @right 評価するprj順位文字列 23 * @return 0 支配関係にない 24 * 0より大きい left が right を支配している 25 * 0より小さい left が right に支配されている 26 */ 27private static int controlTo(String left, String right) { 28 // 構成するプロジェクトの数が違う場合 29 if(left.charAt(0) != right.charAt(0)) { 30 return 0; 31 } 32 33 boolean isLeft = false; 34 boolean isRight = false; 35 // 先頭からプロジェクトごとの順位を確認 36 for (int i = 0; i < left.length(); i++) { 37 if (left.charAt(i) > right.charAt(i)) { 38 isLeft = true; 39 } else if (left.charAt(i) < right.charAt(i)) { 40 isRight = true; 41 } else { 42 // same 43 } 44 } 45 46 if (isLeft ^ isRight) { 47 if (isLeft) { 48 return 1; // left が right を支配している 49 } else { 50 return -1; // right が left を支配している 51 } 52 } 53 54 // 支配関係にない 55 return 0; 56} 57
使い方
例えば(1){A社1位,B社1,C社1位}と(2){A社2位,B社1位,C社1位}の組み合わせがあった場合、
B社,C社の順位は同じ1位ですが、A社に関しては(1)が1位,(2)が2位なので
(2)の組み合わせは(1)の組み合わせに含まれている(=支配されている)と言います。
java
1String kakko1 = toHyoukaStr(0, 3, 6); // (1){A社1位,B社1,C社1位} 2String kakko2 = toHyoukaStr(1, 3, 6); // (2){A社2位,B社1位,C社1} 3 4System.out.println("(1)が(2)を支配しているか?" + (controlTo(kakko1, kakko2) > 0)); // true 5
使い方2(配列の場合)
3レコード目、A社1位、B社2位、C社2位
5レコード目、A社2位、B社3位、C社2位
において、3レコード目は1レコード目に支配されているということになります。
※「5レコード目は3レコード目に支配されている」の誤字だと思ってますが・・・
java
1int[] rec3 = {0, 4, 7}; // 3レコード目、A社1位、B社2位、C社2位 2int[] rec5 = {1, 5, 7}; // 5レコード目、A社2位、B社3位、C社2位 3 4System.out.println("3レコード目が5レコード目を支配しているか?" + (controlTo(toHyoukaStr(rec3), toHyoukaStr(rec5)) > 0)); // true 5System.out.println("5レコード目が3レコード目に支配されているか?" + (controlTo(toHyoukaStr(rec5), toHyoukaStr(rec3)) < 0)); // true 6
こんな感じで比較して、ArrayListかなんかに評価文字列か、配列そのものを保存していけばよいかと思います。
が、まずは支配関係のチェックについての単純なif文なので、実装してもらうしかないですね。
投稿2020/07/31 13:30
編集2020/07/31 13:40総合スコア4826
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。