2012-04-12 38 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; 
} 
} 

而我的puzzle.Row類。

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 2012-05-11 09:19:21

回答

2

我想我剛解決了這個任務。儘管問了這個問題已有兩個月了,但我認爲這看起來像是一個有趣的問題,所以我給了它一個鏡頭。由於「家庭作業」標籤(即使在2個月後),我不想發佈我的代碼,所以我只會描述我的方法。我使用Python,但我會嘗試將任何術語轉換爲Java。

首先,我覺得你跟蹤的方式比你需要的更多的數據。我只保留了一個雙精度數組列表,任何雙精度值爲i,i稱爲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並給出一個二叉樹,從根開始,您首先嚐試全部離開。然後,你嘗試去所有的左邊,但最後一個節點。等等。除了「左」和「右」之外,請考慮「3」和「4.5」,其中節點的值是寬度,並且一旦寬度變得大於所需的寬度,您將停止遍歷樹,width。如果找到一個值爲width的節點,那麼該路徑現在是可能的行,請記住它。換句話說,您首先嚐試N個3x1塊(例如width + 2.5 >= N*3 >= width),從左至右建立行。然後嘗試(N-1)3x1塊和1 4x1塊(4x1是最右邊的塊)。然後(N-2)3x1s,一個4x1和另一個3x1。等等。沒有移位,沒有rowConfig變量,只是一個塊寬度的ArrayList。此外,由於您有系統地遍歷每條路徑(即嘗試每個組合)一次且只有一次,所以您知道您已嘗試過每種組合,並且您知道沒有重複。

現在,建造你的牆。這也可以被視爲修改後的DFS。設想一棵n元樹,其中n等於寬度爲width的潛在行數。使用相同的系統方法,嘗試每條路徑,直到你有一個高度爲height的牆(因爲每行的高度爲1)。但請記住,如果沒有任何間隙是相鄰的,則只需要遍歷路徑。嘗試從底部開始一排一排地修建牆。通過在牆的頂部添加一個新行,當且僅當它沒有任何間隙與頂行中的間隙相鄰時,可以相信您的局部牆總是有效的。在那裏,一旦你點擊了height,你就知道你有一面有效的牆。記錄路徑並繼續,直到沒有更多有效的路徑可供探索。

對於在您還在做任務時不回答,我表示歉意。我很想知道你的最終解決方案與我的不同。

+0

+1未明確發佈答案,因爲它被標記爲「家庭作業」:) – kentcdodds 2012-06-14 16:27:57