1. 程式人生 > 實用技巧 >木棒(深搜 剪枝)

木棒(深搜 剪枝)

喬治拿來一組等長的木棒,將它們隨機地砍斷,使得每一節木棍的長度都不超過50個長度單位。

然後他又想把這些木棍恢復到為裁截前的狀態,但忘記了初始時有多少木棒以及木棒的初始長度。

請你設計一個程式,幫助喬治計算木棒的可能最小長度。

每一節木棍的長度都用大於零的整數表示。

輸入格式
輸入包含多組資料,每組資料包括兩行。

第一行是一個不超過64的整數,表示砍斷之後共有多少節木棍。

第二行是截斷以後,所得到的各節木棍的長度。

在最後一組資料之後,是一個零。

輸出格式
為每組資料,分別輸出原始木棒的可能最小長度,每組資料佔一行。

資料範圍
資料保證每一節木棍的長度均不大於50。

輸入樣例:
9
5 2 1 5 2 1 5 2 1
4
1 2 3 4
0
輸出樣例:
6
5

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 100;
bool state[N];
int w[N];
int sum;
int n;
int length ;
bool dfs(int u ,int s , int start)
{
    if(u * length == sum)return true;
    if(s == length) return dfs(u+1,0,0);
    
    for(int i = start ; i < n ; i ++)
    {
        
        if(s + w[i] > length) continue;
        if(state[i])continue;
        if(!state[i])
        {
            state[i] = true;
            if(dfs(u,s+w[i], i +1)) return true;;
            state[i] = false;
        }
            
    if(!s) return false;//第一個木棍失敗回溯 長度為0  後面的都失敗
    
    if(s + w[i] == length) return false; // 最後一個木棍失敗
     int j = i;
    while(  j < n && w[i] == w[j] ) j ++;//相同木棍失敗 
    i = j-1;

    }
    
    

    
    return false;
    
}


int main()
{
  while(cin >> n , n)
  {
      memset(state,0,sizeof state);
      sum = 0;
      for(int i =0 ; i < n ; i ++)
      {
          cin >> w[i];
          sum +=w[i];
          }
          sort(w,w+n);
          reverse(w,w+n);//搜尋剪枝
          
         length = 1;//列舉大棍長度
        
        while(true)
        {
            if(sum % length == 0 && dfs(0,0,0))//可行性剪枝
            {
                cout << length<<endl;
                break;
            }
            length++;
        }
         
  }
  return 0;
}