1

文字列の代わりに私が書いたいくつかのクラスを使用しているため、実際の問題は少し複雑ですが、次のように想像できます。700の3文字の単語のリストがある場合、どのようにしてすべての組み合わせを見つけることができますか?これらの単語の5つを最初と最後の文字でリンクすることで形成できます。つまり、CAT TOW WAR RAD DOGは成功しますが、CAT TOW WARRAGGODも成功します。

これまでのところ、私はこのようなものを持っています:

for(int i = 0; i < list.size(); i++){
    String temp = chainMaker(list.get(i), list, used, temp);
}

public String chainMaker(String toAdd, ArrayList<String> unused,
    ArrayList<String> used, String result){

    if(result.size() >= 15)
        return result;
    else{
        if(result.canAdd(toAdd))
            result.add(toAdd);
        used.add(toAdd);

        return chainMaker(unused.remove(0), unused, used, result);
    }

    return result;
}

しかし、これは生産するゴミを追加し続けるだけです。私は再帰的なバックトラックがひどいので、この例を機能させることができれば、最終的にこの概念を理解できると思います。賢い人を助けてください!

4

4 に答える 4

0

Javaでの私の試みは次のとおりです。

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class So3206795 {

  static void step(List<String> result, List<String> unused, String requiredStart) {
    if (result.size() == 3) {
      System.out.println(result);
      return;
    }

    for (int i = 0; i < unused.size(); i++) {
      String s = unused.get(i);

      if (s.startsWith(requiredStart)) {
        unused.remove(i); // will be put back later
        result.add(s);

        step(result, unused, s.substring(s.length() - 1));

        result.remove(result.size() - 1);
        unused.add(i, s);
      }
    }
  }

  public static void main(String[] args) {
    List<String> words = Arrays.asList("CAT", "TOW", "WAR", "RAG", "GOD", "ROR");
    // make a modifiable copy of the words
    List<String> unused = new ArrayList<String>(words);
    step(new ArrayList<String>(), unused, "");
  }
}
于 2010-07-08T19:00:42.920 に答える
0

すべての組み合わせを調べているので、ツリーとグラフのトラバーサル アルゴリズムを確認する必要があります。それらはうまく機能し、実績のあるアルゴリズムを使用できます。「文字リンク」制約があることを考えると、トラバーサルでヒューリスティックまたはルールを使用するトラバーサル アルゴリズムにも注目する必要があります。これを行うためのより高度な方法が他にもあると確信していますが、小さなデータセットのツリーとグラフで機能する可能性があります。

于 2010-07-08T18:38:19.343 に答える
0

これは C++ の実装ですが、ロジックは明らかだと思います。何かわからないことがあれば聞いてください。

void letterChain(string stack[5], int k, const vector<string> &words)
{
    if ( k == 5 ) // have 5 words, print solution
    {
        for ( int i = 0; i < 5; ++i )
            cout << stack[i] << " ";
        cout << endl;

        return;
    }

    for ( int i = 0; i < words.size(); ++i ) // try to put a word at the current level of the stack
    {
        // if words[i] is already used, we cant use it again (if we can, just remove this part)
        bool used = false;
        for ( int j = 0; j < k; ++j )
            if ( stack[j] == words[i] )
                used = true;

        if ( !used ) // remove this if you can use a word multiple times
        {
            if ( k == 0 || words[i][0] == stack[k - 1][2] ) // if the letters match
            {
                stack[k] = words[i]; // add it to the stack
                letterChain(stack, k + 1, words); // recursive call
            }
        }
    }
}

int main()
{
    vector<string> words;
    words.push_back("CAT");
    words.push_back("TOW");
    words.push_back("WAR");
    words.push_back("RAD");
    words.push_back("DOG");
    words.push_back("GOD");
    words.push_back("RAG");
    words.push_back("RAR");

    string stack[5];

    letterChain(stack, 0, words);
}

キャット トー ウォー ラッド ドッグ
キャット トー ウォー ラグ ゴッド
キャット トゥ ウォー RAR RAD
キャット トゥ ウォー RAR ラグ
トゥ ウォー ラッド ドッグ ゴッド
トゥ ウォー ラグ ゴッド ドッグ
トゥ ウォー RAR RAD ドッグ
トゥ ウォー RAR ラグ ゴッド
ウォー RAR RAD ドッグ ゴッド
ウォー RAR ラグ ゴッド ドッグ

リストに表示されている回数しか単語を使用できない場合は、カウント ベクトルを使用して、使用するたびにその単語のカウントを減算します。

于 2010-07-08T18:52:25.080 に答える
0

以下は、あなたの投稿を読み間違えたことに基づいています。私はあなたを楽しませるためにそれを残します。本当の解決策は記事の最後にあります。


700 個のオブジェクトのプールから 5 語のすべての可能性を計算しますか?

この問題を解決するための私のクラスは次のとおりです。

public class SO3206795 {

    private static long ct;
    private static List<String[]> allPossibleWords(final Set<String> words, final String[] chain) {
        final List<String> usedWords = Arrays.asList(chain);
        final int offset = usedWords.lastIndexOf(null);
        List<String[]> wordsList;
        if (offset < 0) {
            wordsList = Collections.singletonList(chain);
            logCreated();
        } else {
            wordsList = new ArrayList<String[]>();
            for (final String word : words) {
                final String[] copy = Arrays.copyOf(chain, chain.length);
                if (!usedWords.contains(word)) {
                    copy[offset] = word;
                    wordsList.addAll(allPossibleWords(words, copy));
                }
            }
        }
        return wordsList;
    }

    private static List<String[]> getChains(final Set<String> words, final int length) {
        final List<String[]> tmpChain = new ArrayList<String[]>();
        final String[] chain = new String[length];
        tmpChain.addAll(allPossibleWords(words, chain));
        return tmpChain;
    }
    private static Set<String> getWords(final int count, final int letters) {
        final Set<String> set = new TreeSet<String>();
        final int[] arr = new int[letters];
        int tempCt = 0;
        while (tempCt++ < count) {
            set.add(nextWord(arr));
            for (int i = letters - 1; i >= 0; i--) {
                if (arr[i] == 25) {
                    arr[i] = 0;
                } else {
                    arr[i] = arr[i] + 1;
                    break;
                }
            }
        }
        return set;
    }

    private static void logCreated(){
        if(++ct%10000==0){
            System.out.println("Created "+ct+" chains");
        }
    }

    public static void main(final String[] args) {
        String[]usedArgs=args;
        if(args.length==1&&args[0].matches(".*\\D.*")){
            usedArgs=args[0].split("\\D+");
        };
        final int[] values = {10,3,5};
        for (int i = 0; i < usedArgs.length&&i<values.length; i++) {
            values[i] = Integer.parseInt( usedArgs[i]);
        }
        final SO3206795 thing = new SO3206795(values[0],values[1],values[2]);
        for (final String[] chain : thing.chains) {
            System.out.println(Arrays.toString(chain));
        }
    }

    private static String nextWord(final int[] arr) {
        final char[] ch = new char[arr.length];
        for (int i = 0; i < arr.length; i++) {
            final int j = arr[i];
            ch[i] = (char) (65 + j);
        }
        return new String(ch);
    }

    private static void printInfo(final int numberOfWords, final int wordLength, final int chainLength) {
        BigInteger words = BigInteger.valueOf(numberOfWords);
        for(int i = 1; i < chainLength; i++){
            words=words.multiply(BigInteger.valueOf(numberOfWords-i));
        }

        System.out.println(MessageFormat.format(
            "Creating {0} words of length {1}.\nCreating all possible chains of {2} words.\nThat''s {3} chains in total",
            numberOfWords, wordLength, chainLength, words.toString()));
    }

    Set<String>     words;

    List<String[]>  chains;
    public SO3206795(final int numberOfWords, final int wordLength, final int chainLength) {

        printInfo(numberOfWords,wordLength, chainLength);
        this.words = getWords(numberOfWords, wordLength);
        this.chains = getChains(this.words, chainLength);
    }

}

これには、最大 3 つの引数で呼び出すことができる main メソッドがあります。

  • numberOfWords (生成される単語の数、デフォルト: 10)
  • wordLength (語長、デフォルト: 3)
  • chainLength (単語チェーンの長さ、デフォルト: 5)

ただし、値 700、3、5 で起動すると、デバッグ出力は次のようになります。

Creating 700 words of length 3.
Creating all possible chains of 5 words.
That's 165680980516800 chains in total

かなり多いと思いませんか?それが 700 * 699 * 698 * 697 * 696 の合計です。文字列ではなく独自のオブジェクトを使用していて、オブジェクトのサイズがそれぞれわずか 3 バイトであるとしましょう。これは、メモリ消費量が

497042941550400 Bytes  or
485393497607 KB        or
474017087 MB           or
462907 GB              or
452 TB                 

あなたのことは知りませんが、私のマシンの RAM よりもはるかに多くの RAM が搭載されています。残念ながら、オブジェクトがそれぞれ 3 バイトしかない可能性はほとんどありません (また、作成されたリストと配列にもかなりのメモリが必要です)。だから、コーディングが楽しかったとしても、すべての可能性を計算するのは良い考えではないと思います。

また、それには長い時間がかかります。私のマシンでは、10000 チェーンを作成するのに約 16 ミリ秒かかります。したがって、165680980516800 チェーンの場合、合計持続時間は

2650895688268 ms      or
2650895688 sec        or
44181594 min          or
736359 hours          or
30681 days            or
84 years

ディープ ソートが答え 42 を導き出すのに 750 万年かかったので、おそらくそれほど長くはありませんが、おそらくあなたが待つよりも長いでしょう。

お願い: 私の数学はひどいものです.なぜこれがすべてナンセンスなのか誰かが私に説明してくれたら、私はもっとうれしいです.


誤解の終わり:

くそー、私は文字リンクの制約を逃しました。これが私の更新されたソリューションです。上記のメソッド allPossibleWords を次の 2 つのメソッドに置き換えます。

private static List<String[]> allPossibleWords(final Set<String> words, final String[] chain) {
    final List<String> usedWords = Arrays.asList(chain);
    final int offset = usedWords.lastIndexOf(null);
    List<String[]> wordsList;
    if (offset < 0) {
        wordsList = Collections.singletonList(chain);
        logCreated();
    } else {
        wordsList = new ArrayList<String[]>();
        for (final String word : words) {
            if (!usedWords.contains(word)&&(offset==chain.length-1||isLegalNeighbor(word,usedWords.get(offset+1)))) {
                final String[] copy = Arrays.copyOf(chain, chain.length);
                copy[offset] = word;
                wordsList.addAll(allPossibleWords(words, copy));
            }
        }
    }
    return wordsList;
}
private static boolean isLegalNeighbor(final String left, final String right) {
    return left.charAt(left.length()-1)==right.charAt(0);
}

また、getWords をよりランダムなバージョンに置き換えます。

private static Set<String> getWords(final int numberOfWords, final int wordLength) {
    final Set<String> set=new TreeSet<String>();
    final Random r = new Random();
    while(set.size()<numberOfWords){
        final char[] ch = new char[wordLength];
        for (int i = 0; i < ch.length; i++) {
            ch[i]=(char) (65+r.nextInt(26));
        }
        set.add(new String(ch));
    }
    return set;
}

現在、実際には 200 語で妥当な実行時間を得ていますが、700 語では、永遠に思えるものの後に OutOfMemoryError が依然として作成されます。

とにかく、これがPastebin の完全な解決策です。

そして、ここに修正された数学があります:

約 362559479 の可能な組み合わせがあります

700 * (699/26) * (698/26) * (697/26) * (696/26)

オブジェクト サイズが 3 バイトの場合、メモリ消費量は

1087678437 Bytes  or
1062185 KB        or
1037 MB           or
1 GB

私のマシンでは、文字リンクで 10000 チェーンを作成するのに約 500 ミリ秒かかります。したがって、362559479 チェーンの合計期間は

181279739 ms      or
181279 sec        or
3021 min          or
50 hours          or
2 days            

これらはまだ印象的な数字だと思います

于 2010-07-09T00:25:53.117 に答える