2012-04-12 16 views
9

3x1と4.5x1のブロックからパネルを作成する必要があるプロジェクトがあります。構造的完全性のために、ブロック間のスペースは隣接する行に並んではいけません。すべての可能な組み合わせを計算する必要があります。 7.5x1パネルには2つのソリューションがあり、7.5x2パネルには2つのソリューションがあり、12x3パネルには4つの方法があり、27x5には7958通りの方法があります。私の問題は、私がより高い幅に立ち上がって、もっと解決策を得ているときです。これは、重複するテーブルを取得している可能性があることと関係していると思いますが、どこにあるのか、それを修正する方法がわかりません。どんな助けでも大歓迎です。コードは以下のとおりです。ブロックとのユニークなパネルの組み合わせ - Javaのコード

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

import puzzle.Row; 

public class panel { 
/** 
* This program will return the number of unique tables that for structural  integrity don't have blocks that line up 
* in adjacent rows. The width is to be between 3 and 48 and the height between 1 and 10. The width 
* should also be a multiple of 0.5. 
* 
* @param width, height 
* @return totalTables 
*/ 
public static void main(String[] args) { 
    int width = 0; 
    int height = 0; 

    // Check to make sure that two arguments were passed. 
    if (args.length != 2) { 
     System.out.println("Please enter both a height and a width."); 
     System.exit(1); 
    } else { 
     // Check that a data type of double was entered. 
     if ((args[0].matches("^[0-9]+(\\.[0-9]+)?$")) && 
       (Double.valueOf(args[0].trim()).doubleValue() >= 3.0) && 
       (Double.valueOf(args[0].trim()).doubleValue() <= 48.0) && 
       (Double.valueOf(args[0].trim()).doubleValue()) % 0.5 == 0) { 
      width = (int) (Double.valueOf(args[0].trim()).doubleValue() * 2); // Double the width so that we are working with an integer. 
     } else { 
      System.out.println("Please enter a number for your width that is between 3 and 48 and divisable by 0.5."); 
      System.exit(1); 
     } 
     // Check that a data type of integer was entered. 
     if ((args[1].matches("^[0-9]+$")) && (Integer.valueOf(args[1]) >= 1) && (Integer.valueOf(args[1]) <= 10)) { 
      height = Integer.valueOf(args[1].trim()).intValue(); 
     } else { 
      System.out.println("Please enter an integer for your height that is between 1 and 10."); 
      System.exit(1); 
     } 

     List<Row> allRows = new ArrayList<Row>(); // Holds all the possible rows and needed information 
     findAllRows(width, 0, 0, allRows); 
     findMatches(allRows); 
     long totalTables = findUniqueTables(allRows, height); 
     System.out.println(totalTables); 
    } 
} 

/** 
* Recursively calculates all possible row combinations for supplied width. 
* Row configuration is stored in binary format with 1 indicating gaps. Each bit is 
* represented by 3 inches. The bits 1, 2, nth are dropped as they are not needed. 
* 
* i.e. width of 12 would produce 
* width = 12 * 2 = 24 
* 
* Bricks    Binary    Stored Binary Decimal Value 
* 6 x 6 x 6 x 6  0 1 0 1 0 1 0 1  1 0 1 0 1  21 
* 9 x 9 x 6   0 0 1 0 0 1 0 1  0 1 0 0 1  9 
* 9 x 6 x 9   0 0 1 0 1 0 0 1  0 1 0 1 0  10 
* 6 x 9 x 9   0 1 0 0 1 0 0 1  1 0 0 1 0  18 
*/ 

public static void findAllRows(int width, int currLen, int rowConfig, List<Row> root) { 
    if (currLen + 6 == width) { 
     root.add(new Row(width, rowConfig)); // Add current row configuration as an acceptable row. 
     return; 
    } else if (currLen + 9 == width) { 
     rowConfig = rowConfig << 1; 
     root.add(new Row(width, rowConfig)); // Add current row configuration as an acceptable row. 
     return; 
    } else if (currLen + 6 > width) { 
     return; // Current configuration is longer than the width is allowed. Do not add. 
    } else { 
     int nextConfig = (rowConfig << 2) + 1; // 
     findAllRows(width, currLen + 6, nextConfig, root); 

     nextConfig = (rowConfig << 3) + 1; 
     findAllRows(width, currLen + 9, nextConfig, root); 
    } 
    return; 
} 

/** 
* Finds all possible row matches for the given row that do not have gaps that line up. 
*/ 
public static void findMatches(List<Row> rows) { 
    for (Row row : rows) { 
     for (Row rowC : rows) { 
      if (matchesBelow(row.getGaps(), rowC.getGaps())) { 
       row.addChilcRows(rowC.getGaps()); 
      } 
     } 
    } 
} 

/** 
* Does a bitwise AND to see if there are any gaps that line up. If there are no gaps then 
* the resulting AND should equal to 0. 
*/ 
public static boolean matchesBelow(int row, int rows) { 
    if ((row & rows) == 0) { 
     return true; 
    } else { 
     return false; 
    } 
} 

/** 
* Finds all the unique tables and returns the count. 
*/ 
public static long findUniqueTables(List<Row> allRows, int height) { 
    long tableCount = 0; 
    for (Row row : allRows) { 
     tableCount += findTables(row, height); 
    } 
    return tableCount; 
} 


/** 
* This makes all possible tables. 
*/ 
public static long findTables(Row row, int tableHeight) { 
    long count; 
    if (tableHeight == 1) { 
     return 1; 
    } else { 
     count = 0; 
     for (int i = 0; i < row.getChildRowsSize(row); i++) { 
      count += findTables(row, tableHeight -1); 
     } 
    } 
    return count; 
} 
} 

そして私のパズル。低クラス。

package puzzle; 

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

public class Row { 
int gaps; 
int width; 
List<Long> potChildRows = new ArrayList<Long>(); 

public Row(int width, int gaps) { 
    this.gaps = gaps; 
    this.width = width; 
} 

public int getGaps() { 
    return this.gaps; 
} 

public int getWidth() { 
    return this.width; 
} 

public long getChildRowsSize(Row row) { 
    return row.potChildRows.size(); 
} 

public void addChilcRows(long row) { 
    this.potChildRows.add(row); 
} 
} 
+1

失敗したケースを教えてください。 「27x5には7958通りの方法がありますか」はエラーの場合を表していますか?はいの場合は、どちらが解決策ですか?そうでない場合は、失敗したケースを提供できますか? – Zecas

答えて

2

私はちょうど課題を解決したと思います。質問をしてから2ヶ月が経過していたにもかかわらず、私はそれを解決するのが楽しい問題のように思ったので、私はそれを撃った。私は "宿題"タグ(2ヶ月後も)のために自分のコードを投稿したくないので、私は私のアプローチを説明します。私はPythonを使用しましたが、私はどの用語もJavaに翻訳しようとします。

まず、必要以上に多くのデータを追跡しているような気がします。私はdoubleのArrayListを保持していたので、doubleの場合はiiはix1ブロックを参照していました。リストは、row[0]が最も左側のブロックで、row[row.length-1]が最も右側のブロックであるように指示されました。たとえば、[3, 3, 4.5]は、左から右に、3x1ブロック、別の3x1ブロック、および4.5x1ブロックを使用する長さ10.5の行を指します。このシンプルな構造を使用して、自分の設定を簡単に視覚化することができます。行の長さは、すべての要素を一緒に追加する(つまり3 + 3 + 4.5 = 10.5)と同じくらい簡単です。私のギャップは、私のリストを繰り返す間に(つまり、私のギャップは33 + 3 = 6です)、実行中の合計を維持するのと同じくらい簡単です。この単純なデータ型を使用すると、コードを大幅に単純化することができます。

また、この問題を変更されたDepth-First Searchと考えることが役立つことがわかりました。 DFSを使用し、バイナリツリーが与えられている場合は、ルートから始めて、すべて左に移動してみてください。次に、最後のノードを1つ左に移動しようとします。等々。 "left"と "right"の代わりに、 "3"と "4.5"を考えてください。ノードの値は幅で、幅が所望の幅より大きくなるとツリーを横切ることを止めます。width正確にwidthの値を持つノードを見つけた場合、そのパスは現在可能な行になります。覚えておいてください。言い換えれば、最初にN 3×1ブロック(例えば、width + 2.5 >= N*3 >= width)を試して、左から右へ行を構築します。次に(N-1)個の3x1ブロックと1個の4x1ブロックを試してみましょう(4x1が最も右にあります)。次に(N-2)3x1s、1つは4x1、もう1つは3x1。等々。ビットシフトはありません。rowConfig変数ではなく、ブロック幅のArrayListだけです。また、各パスを体系的に(つまり各組み合わせを試して)1回だけ移動したので、すべての組み合わせを試したことがあり、重複がないことがわかります。

あなたの壁を築きましょう。これは変更されたDFSとしても扱うことができます。 nが、幅がwidthの潜在的な行の数に等しいn-aryツリーを想像してください。同じ、系統的なアプローチを使用して、壁の高さがheight(各行の高さが1であるため)まですべてのパスを試してください。しかし、隙間のどれもが隣接していない場合にのみ、パスをたどることを忘れないでください。下から上に向かって、一度に1つの行を構築してみてください。壁の一番上に新しい行を追加すると、上の行のギャップに隣接するギャップがない場合に限り、部分壁が常に有効であると確信することができます。そこには、一度heightを押すと、あなたは有効な壁があることを知っています。パスを記録し、有効なパスがなくなるまで続けてください。

あなたが依頼をしている間は、私はお詫び申し上げます。あなたの最終的な解決策が私とどのように違うかを知りたいと思っています。

+0

+1は「宿題」とタグ付けされているため、答えを明示的に投稿していない – kentcdodds

関連する問題