zoukankan      html  css  js  c++  java
  • Sticks(poj1011/uva307)

    题目大意:

    乔治有一些碎木棒,是通过将一些相等长度的原始木棒折断得到的,给出碎木棒的总数和各自的长度,求最小的可能的原始木棒的长度;(就是将一些正整数分组,每组加起来和相等,使和尽可能小)

    一开始做poj 32ms过,但uva3000 ms 都超时。。。而且poj discuss里给出了一组bT数据,最后uva 0.2sac的代码也跑了3 。4秒左右。discuss里的大牛据说什么奇偶性剪枝0.01ms过,可惜搜了半天也没找到具体方法。这题就这样过好了。。(参考各种空间博客才艰难ac。不过此题实在是太经典了,搜索学习剪枝必做) 

    对于这道题而言,剪枝的策略一般有下面6个:

    ①先将木棒长度从大到小进行排序,这样便于后面的选择和操作,是后面一些剪枝算法的前提。

    ②在枚举原木棒长度时,枚举的范围为max与sum/2之间,如果这个区间内没有找到合适的长度,那么最后原木棒的长度只能是sum。

    ③枚举的原木棒的长度只能是sum的约数。

    ④在深搜过程中,如果当前木棒和前一个木棒的长度是一样的,但是前一个木棒没有被选上,那么这个木棒也一定不会被选上。

    ⑤在深搜过程中,如果当前是在拼一根新木棒的第一截,但如果把可用的最长的一根木棒用上后不能拼成功的话,那么就不用再试后面的木棒了,肯定是前面拼的过程出了问题。

    ⑥在深搜过程中,如果当前可用的木棒恰好能补上一根原木棒的最后一截,但用它补上之后却不能用剩下的木棒完成后续的任务,那么也不用再试后面的木棒了,肯定是前面拼的过程出了问题。

    参考博客:http://www.cnblogs.com/staginner/archive/2011/09/08/2171329.html

    我的AC 代码:(剪枝见注释)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
     
    int n,max_len,min_len,sum,ans,num,flag;
    int a[10000],v[10000];
     
    bool cmp(const int &x,const int &y)
    {
         return !(x<y);
    }
     
    void search(int step,int from,int cur)//step表示当前去凑的是第几根原始棒,order表示当前用了多少根碎棒子来凑第step根
    {
         //printf("%d %d ",step,cur);
        if (cur==ans)
        {
           if (step==num)
           {
              flag=1;
              return;
           }
           int k;
           for (k=1;k<=n && v[k];k++);
           v[k]=1;
           search(step+1,1,a[k]);
           v[k]=0;
           return;
        }
        for (int i=from;i<=n;i++)
        {
            if (v[i])
               continue;
            if (cur+a[i]>ans)
               continue;
            if (a[i]==a[i-1] && !v[i-1])
               continue;//剪枝3:上一根棒和目前这根一样并且没用过,那么用这一根去凑和用上一根去凑结果一样都不能出解
            //printf("kk %d %d ",cur,cur+a[i]);
            int t=a[i]+cur;
            if (t!=ans && t+min_len>ans)
               continue;
            v[i]=1;
            search(step,i+1,t);
            v[i]=0;
            if (t==ans)
               return;
            if (flag || cur==0)//剪枝4:如果当前用了1根碎棒子来凑,枚举了第一根碎棒不能出解那么跳出
               return;
        }
        return;
    }
     
    int main ()
    {
        while (scanf("%d",&n)==1)
        {
              if (n==0)
                 break;
              v[0]=1;
              a[0]=210000000;
              max_len=-1;
              min_len=21000000;
              sum=0;
              flag=0;
              for (int i=1;i<=n;i++)
              {
                  scanf("%d",&a[i]);
                  if (a[i]>max_len)
                     max_len=a[i];
                  if (a[i]<min_len)
                     min_len=a[i];
                  sum+=a[i];
              }
              sort(a+1,a+n+1,cmp);
              for (ans=max_len;ans<=sum/2;ans++)//剪枝1:答案的下界为最长的棒,上界为长度总和
              {
                  if (sum%ans!=0)
                     continue;//剪枝 2:原始棒长度是总长度的约数
                  for (int k=1;k<=n;k++)
                      v[k]=0;
                  num=sum/ans;
                  search(1,1,0);
                  if (flag)
                  {
                      printf("%d ",ans);
                      break;
                  }
              }
              if (!flag)
                 printf("%d ",sum);
        }
        return 0;
    }
    Every day is meaningful, keeping learning!
  • 相关阅读:
    基于Asp.Net webApi owin oauth2的实现
    动态赋值
    C#生成二维码
    深度学习中反卷积层(转置卷积)引起的棋盘格噪声
    batch normalization 批归一化 --- 一个硬币的两面
    FFMPEG常用命令-格式转换-持续更新中
    [译]CRF和QP的区别
    读懂NCHW和NHWC
    [译]GPUView
    有一次接口设计
  • 原文地址:https://www.cnblogs.com/vb4896/p/3874620.html
Copyright © 2011-2022 走看看