• [ SHOI 2001 ] 化工厂装箱员


    (\)

    (Description)


    传送带上按顺序传过来(N)个物品,一个有(A,B,C)三类。

    每次装箱员手里只能至多拿十个,然后将手中三类物品中的一类装箱,才能接着拿或接着装箱,求完成整个序列的最少装箱次数。

    • (Nin [1,100])

    (\)

    (Solution)


    这数据范围不是搜索乱搞

    • (DP)。设(f[s][i][j][k])表示,当前已经取走了前(s)个,(A)类手里有(i)个,(B)类手里有(j)个,(C)类手里有(k)个,其余取出的全部已经装箱时,最少总装箱次数。有显然边界(f[0][0][0][0]=1)

    • 于是暴力枚举状态,复杂度是( ext O(100 imes 10^3)= ext O(10^5))的。转移考虑先将手里的东西拿满,再放下其中一类物品。即计算将要达到的位置(s'),到(s')时手里三类物品的个数(x,y,z),然后就只需要考虑放下哪一类的问题了。

      f[sum][0][y][z]=min(f[sum][0][y][z],f[s][i][j][k]+1);
      f[sum][x][0][z]=min(f[sum][x][0][z],f[s][i][j][k]+1);
      f[sum][x][y][0]=min(f[sum][x][y][0],f[s][i][j][k]+1);
      
    • 注意到达位置需要考虑序列的边界,答案即为(f[n][0][0][0])

    (\)

    (Code)


    #include<cmath>
    #include<cstdio>
    #include<cctype>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define N 110
    #define R register
    #define gc getchar
    #define inf 2000000000
    using namespace std;
    
    char c;
    int n,ans=inf,a[N],f[N][11][11][11];
    
    int main(){
      scanf("%d",&n);
      for(R int i=1;i<=n;++i){
        c=gc();
        while(!isalpha(c)) c=gc();
        a[i]=(c=='A'?0:(c=='B'?1:2));
      }
      for(R int s=0;s<=n;++s)
        for(R int i=0;i<=10;++i)
          for(R int j=0;j<=10;++j)
            for(R int k=0;k<=10;++k) f[s][i][j][k]=inf;
      f[0][0][0][0]=0;
      for(R int s=0;s<=n;++s)
        for(R int i=0;i<=10;++i)
          for(R int j=0;j<=10;++j)
            for(R int k=0,sum,x,y,z;k<=10;++k)
              if(f[s][i][j][k]<inf){
                sum=min(n,s+(10-i-j-k)); x=i; y=j; z=k;
                for(R int p=s+1;p<=sum;++p) a[p]==0?++x:(a[p]==1?++y:++z);
                f[sum][0][y][z]=min(f[sum][0][y][z],f[s][i][j][k]+1);
                f[sum][x][0][z]=min(f[sum][x][0][z],f[s][i][j][k]+1);
                f[sum][x][y][0]=min(f[sum][x][y][0],f[s][i][j][k]+1);
              }
      printf("%d
    ",f[n][0][0][0]);
      return 0;
    }
    
  • 相关阅读:
    android的原理,为什么我们不需要太多的剩余内存(转)
    简单制作RPM二进包实例(转)
    电源相关术语
    Linux 查找指定文件并删除
    Linux内核中的内存屏障(转)
    分压、分流原理
    Linux内核入门—— __attribute__ 机制
    如何手工释放linux内存
    多核编程中的负载平衡难题(转)
    linux2.6.26内核中ARM中断实现详解(转)
  • 原文地址:https://www.cnblogs.com/SGCollin/p/9671600.html
Copyright © 2020-2023  润新知