• 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
      ",low);
      83     return 0;
      84 }
      View Code
  • 相关阅读:
    linux下编译sphinx拓展
    Java为什么使用连接池
    内部类之.this&&.new
    何为代理
    Qt install Phonon
    Gcc简介与常用命令
    Vim的设置和使用——编程者
    QT程序启动界面的使用
    slide from one widget to another
    Hide the common top menu in Ubuntu 12.04
  • 原文地址:https://www.cnblogs.com/shangyu/p/3287836.html
Copyright © 2020-2023  润新知