1. 程式人生 > >POJ 1011 Sticks

POJ 1011 Sticks

include nts 代碼 二次 got || bsp clu quicksort

Description

George took sticks of the same length and cut them randomly until all parts became at most 50 units long. Now he wants to return sticks to the original state, but he forgot how many sticks he had originally and how long they were originally. Please help him and design a program which computes the smallest possible original length of those sticks. All lengths expressed in units are integers greater than zero.

Input

The input contains blocks of 2 lines. The first line contains the number of sticks parts after cutting, there are at most 64 sticks. The second line contains the lengths of those parts separated by the space. The last line of the file contains zero.

Output

The output should contains the smallest possible length of original sticks, one per line.

Sample Input

9
5 2 1 5 2 1 5 2 1
4
1 2 3 4
0

Sample Output

6
5

Source

Central Europe 1995 題目大致意思:就是有一個人把幾根木頭切成了幾段,然後現在他想復原這些木棒,但是他又不記得原來有幾根木棒了。求原來木棒的最小長度。 一道典型的DFS題目,而且要不停的剪枝。 1. 所有的木棒都要用到 2.所有木棒的長度可以整除最短的長度 3.最短的長度至少是分成幾段裏面的最長的長度 4.如果現在選中的一根木棒和上一次選中的木棒一樣長,但是上一根木棒沒有被采用,那麽這一根也絕對不會被采用,因為這些木棒只有長度的差異,現在長度都一樣了,那麽就可以看做兩個木棒完全等價,既然上一根都沒有被采用,與它等價的又怎麽可能會被采用呢? 5.如果進行一次搜索以後假定木棒的剩余長度都沒有任何改變(我們用假定木棒的最小長度減枚舉的木棒),那麽這是絕對不正常的情況,因為上面說了,木棒的最小長度應該是切斷木棒裏的最長的長度,也就是說Len>=Stick (Len是假定的最短木棒長度,Stick是任意切斷的木棒長度),如果出現這種情況,那麽我們假定的最小長度失效 6.如果選用的被切斷的木棒長度和剩余的長度一樣,但是最後還是匹配失敗了,那麽這個最短長度也不是正確的,直接返回false 代碼如下:
#include <iostream>

using
namespace std; int used[100]; //判斷第i根木棒是否被采用 int stick[100]; //記錄第i根木棒的長度 void quicksort(int left, int right) { int i, j, temp; if (left < right) { i = left, j = right, temp = stick[i]; while (i < j) { while (i < j&&stick[j] <= temp) j--; stick[i] = stick[j]; while (i < j&&stick[i] >= temp) i++; stick[j] = stick[j]; } stick[i] = temp; quicksort(left, j - 1); quicksort(j + 1, right); } } int DFS(int Len, int left, int len, int n) //Len 每根木棒的長度 left 剩余的木棒 { if (len == 0 && left == 0) return 1; if (len == 0) len = Len; for (int i = 0; i < n; i++) { if (!used[i] && stick[i] <= len) { if (i > 0 && stick[i] == stick[i - 1] && !used[i]) continue; //前面有一根和目前這根一樣長的但是沒有被采用 那麽這根也不會被采用 第二次剪枝 used[i] = 1; if (DFS(Len, left - 1, len - stick[i], n)) return 1; else { used[i] = 0; if (stick[i] == len || len == Len) return 0; //如果這根木棒和剩余長度一樣或者剩余木棒長度沒有改變 那麽絕對不會成功 //因為 如果選中的木棒和剩余的一樣長卻匹配失敗 那麽後面的木棒是沒有希望的 //如果木棒的長度都沒有改變 那假設的長度絕對不會成立的 //第三次剪枝 } } } } int main() { int n, len, sum; while (cin >> n) { sum = 0; //所有木棒的長度和 for (int i = 0; i < n; i++) cin >> stick[i], sum += stick[i]; memset(used, 0, sizeof(used)); quicksort(0, n - 1); //從大到小排列 由於每根木棒都要用到,所以從最大的一根開始,這樣可以減少遞歸次數 len = stick[0]; //木棒最小長度應該是給出的木棒的最大長度 while (1) { if (sum%len == 0) //給出的木棒的總長度一定可以整除單根木棒的長度 第一次剪枝 if (DFS(len, n, len, n)) break; len++; //枚舉木棒的長度 memset(used, 0, sizeof(used)); } cout << len << endl; } }

POJ 1011 Sticks