usaco4.12Fence Rails(迭代加深)

为了这题还去学了下迭代加深 回来还是不会写 

只好参考各大神的代码及题解了

二分枚举最大可以切的块数 然后就是各种分析及优化

USACO题解里写了7个优化。。

问题分析

抽象一下就可以发现,算法的本质是多重背包问题。 补充:这题与破锣乐队都是多个背包,不可重复放物品。区别在于破锣乐队要有顺序,此题不需要,这样此题就必须要搜索才行。 单个背包的问题我们可以用DP解决,但是对于这种问题我们只能用搜索了。 但是可以看一看这道题的数据规模:1<=n<=50,1<=r<=1023。如此大的规模我们只能考虑进一步的优化。

我采用的是dfsid搜索每一个rail来源的board。以下技巧都是针对这种搜索顺序来制定的。 (注:rail是所需要切成的东西,board是供应商提供的原料)

如果使用dancing links的话,可以让程序的常数快2倍。

优化技巧

  1. 很容易就能注意到,由于每块rail的价值是相等的——也就是说切小的要比切大的来的划算。那么我们在搜索能否切出i个rail的方案是自然要选最小的i个rail来切。
  2. 经过一些实验可以发现,先切大的rail比先切小的rail更容易提前出解。同样,[先切小的board比先切大的board更容易提前出解?]{注:好像先切大的board要比先切小的更快}。{*我的程序先切小再切大第5个点就TLE了,而先切大再切小就快很多,见C++程序.{跟我一样,握个手,一定要先大后小!!!}}
  3. 由于r最大可能是1023,但是rail长度的范围却只有0~128,这点提醒了我们有很多rail的长度会是相同的。所以我们要避免冗余,优化搜索顺序。若有rail[i+1]=rail[i],则rail[i+1]对应的board一定大于等于rail[i]对应的board。可以通过这种方法剪掉很多冗余的枝条。
  4. 相应的,如果board[i]=board[i+1],那么从board[i]切下的最大的rail一定大于等于从board[i+1]切下的最大的rail。
  5. 对于切剩下的board(无法再切下rail),统计一下总和。如果这个值大于board长度的总和减去rail长度的总和,一定无解,可以剪枝。这个剪枝最关键。
  6. 二分答案
  7. 其实在读入的过程中,如果rail[i] > max{board} 那么这个rail应该舍去 By Clarkok
  8.  1 /*
     2     ID: shangca2
     3     LANG: C++
     4     TASK: fence8
     5  */
     6 #include <iostream>
     7 #include<cstdio>
     8 #include<cstring>
     9 #include<algorithm>
    10 #include<stdlib.h>
    11 using namespace std;
    12 int bo[55],te[55],ra[1050],v;
    13 int n,m,res,s,sum[1050],flag;
    14 void dfs(int tt,int st)
    15 {
    16     int i;
    17     if(flag) return ;
    18     if(tt==0)//全部可以切完
    19     {
    20         flag = 1;
    21         return ;
    22     }
    23     int ss=0,o;
    24     for(i = 1 ; i <= n ; i++)//当前木板剩余值已经大于最多的剩余值 肯定不用再搜
    25     {
    26 
    27         if(te[i]<ra[1])
    28         ss+=te[i];
    29     }
    30     if(ss>v) return ;
    31     for(i = st ; i <= n ; i++)
    32     {
    33         if(te[i]>=ra[tt])
    34         {
    35 
    36             if(tt-1>=1&&ra[tt]==ra[tt-1])//一个小优化 如果ra[tt]已经在i~N里搜了 那么前面跟它相等的 就不会在i之前搜了
    37             o = i;
    38             else
    39             o = 1;
    40             te[i]-=ra[tt];
    41             dfs(tt-1,o);
    42             te[i]+=ra[tt];
    43         }
    44     }
    45     return ;
    46 }
    47 int main()
    48 {
    49     //freopen("fence8.in","r",stdin);
    50     //freopen("fence8.out","w",stdout);
    51     int i;
    52     cin>>n;
    53     for(i = 1 ; i <= n ; i++)
    54     {
    55         scanf("%d",&bo[i]);
    56         s+=bo[i];
    57     }
    58     sort(bo+1,bo+n+1);
    59     for(i = 1; i <= n ; i++)
    60     te[i] = bo[i];
    61     scanf("%d",&m);
    62     for(i = 1; i <= m ; i++)
    63     {
    64         scanf("%d",&ra[i]);
    65 
    66     }
    67     sort(ra+1,ra+m+1);
    68     for(i = 1; i <= m ; i++)
    69     sum[i] = sum[i-1]+ra[i];
    70     int low=0,high = m;
    71     while(low<high)//二分找一下 满足最多可以切多少块
    72     {
    73         int mm = (low+high+1)>>1;
    74         v = s-sum[mm];
    75         flag = 0;
    76         dfs(mm,1);
    77         if(flag)
    78         low = mm;
    79         else
    80         high = mm-1;
    81     }
    82     printf("%d\n",low);
    83     return 0;
    84 }
    View Code

     

posted @ 2013-08-28 19:36  _雨  阅读(355)  评论(0编辑  收藏  举报