#include <cstdio>
#include <algorithm>
using namespace std;
int len[75],used[75],ans,sum,n;
bool cmp(int a,int b)
{
return a>b;
}
bool check(int pos/*當前小木棍編號*/,int stk/*當前長木棍剩餘長度*/,int alrest/*剩餘小木棍長度總和*/)
{
if (stk==alrest) return true;
if (ans==alrest) return true;
int i;
for (i=1;i<=n;i++)
{
if (!used[i]&&len[i]<=stk)
{
used[i]=1;
if (len[i]==stk)
{if (check(1,ans,alrest-len[i])) return true;}
else if (check(pos+1,stk-len[i],alrest-len[i])) return true;
used[i]=0;
if (stk==len[i]) return false;//如果這根可以,但之後的不行,就不用繼續搜了
if (alrest==sum) return false;//如果第一個不行就不用繼續搜了
if (stk==ans) return false;//如果第一個不行就不用繼續搜了
while (len[i]==len[i+1]) i++;//不重複搜
}
}
return false;
}
int main()
{
while (cin>>n)
{
int sum=0;
if (n==0) break;
for (int i=1;i<=n;i++)
{
cin>>len[i];
sum+=len[i];
used[i]=0;
}
sort(len+1,len+n+1,cmp);
ans=len[1];
int flag=0;
while (ans<=sum&&flag==0)
{
while (sum%ans!=0) ans++;
if (check(1,ans,sum))
{
cout<<ans<<endl;
flag=1;
}
ans++;
}
}
return 0;
}
/*題目大意:給出一些長度不大於 50 的木棍,
要求你把這些小木棍拼成長度相同木棍,當然長度越小越好。
解題思路:
思想很簡單,一個接一個的把木棍拼起來,最後把木棍用光。
關鍵的地方是幾個剪枝技巧:
設所有木棍的總長度爲 Sum, 最終的答案是 L。
1. 首先要明白, Sum一定要能被 L 整除。
2. L 一定 大於等於 題目給出的最長的木棍的長度 Max。
由上述兩點,我們想到,可以從 Max 開始遞增地枚舉 L,
直到成功地拼出 Sum/L 支長度爲 L 的木棍。
搜索中的剪枝技巧:
3. 將輸入的輸入從大到小排序,這麼做是因爲一支長度爲 K
的完整木棍,總比幾支短的小木棍拼成的要好。形象一些:
如果我要拼 2 支長爲8的木棍,第一支木棍我拼成 5 + 3
然後拼第二支木棍但是失敗了,而我手中還有長爲 2 和 1
的木棍,我可以用 5 + 2 + 1 拼好第一支,再嘗試拼第二
支,仔細想一想,就會發現這樣做沒意義,註定要失敗的。
我們應該留下 2+1 因爲 2+1 比 3 更靈活。
我手中有一些木棍, 其中有 2 根長爲 4 的木棍, 當前搜索
狀態是 5+4+.... (即表示長度爲 5,4,2 的三支拼在一起,
...表示深層的即將搜索的部分), 進行深搜後不成功,故我
沒必要用另一個 4 在進行 5+4+...
5. 將開始搜索一支長爲 L 的木棍時,我們總是以當前最長的未
被使用的 木棍開始,如果搜索不成功,那麼以比它短的開始
那麼也一定不能取得全局的成功。因爲每一支題目給出的木棍
都要被用到。如果,有 4 5 4 4 3 2
想拼成長爲 6 的木棍,那麼從 5 開始, 但是顯然沒有能與 5
一起拼成 6 的,那麼我就沒必要去嘗試從 4 開始的,因爲
最終 5 一定會被遺棄。在拼第 2 3 ... 支木棍時,一樣。
6. 最後的最簡單的一個就是,
for(int i = 0; i < n; i++)
for(int j = 0; j < n; j++)
{}
與
for(int i = 0; i < n; i++)
for(int j = i+1; j < n; j++)
{}
的區別,這個不多說了。*/