poj1011

#include
#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++)
    {}
   的區別,這個不多說了。*/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章