poj1011

来源:互联网 发布:111111的网络语意思 编辑:程序博客网 时间:2024/04/28 06:47
#include <iostream>
#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++)
    {}
   的区别,这个不多说了。*/

0 0
原创粉丝点击