[USACO12MAR]摩天大楼里的奶牛Cows in a Skyscraper (状态压缩DP)

不打算把题目放着,给个空间传送门,读者们自己去看,传送门(点我)    

 

这题是自己做的第一道状态压缩的动态规划。

 

思路:

 

在这题中,我们设f[i]为i在二进制下表示的那些牛所用的最小电梯数。

设g[i]为i在二进制下表示的那些牛使用的电梯中剩下的最大容量。

所以很明显的,我们只要枚举每一只牛就可以了。

如果当前状态下,最大容量能装进某只牛,则装进去,并且用两个变量保存装进去后的f值与g值,否则再使用一个新的电梯,并且用变量保存用新电梯后的f与g值。

在每次的枚举,我们还要将当前保存的f值与g值与原来保存的状态值进行对比,取最小的,在这,如果当前枚举的f值与原来保存的f值相等,则我们更新g值,在两者间取最大的即可。

 

其中 i & (1 << j-1) 是判断第j只牛是否在状态i中,i | (1 << j-1) 表示将第j只牛装进去后的状态。

下面贴出代码,有问题下面留言

 

 

#include<cstdio>
#include<algorithm>
#define N 1<<20
using namespace std;

int f[N],g[N],w[20];

int main(){
    int n,c;
    scanf("%d%d",&n,&c);
    for(int i = 1; i <= n; i++)scanf("%d",&w[i]);
    int mxx = (1 << n)-1;                //mxx为最终状态
    for(int i = 0; i <= mxx; i++)f[i] = 19999999,g[i] = c;
    f[0] = 0;
    for(int i = 0; i < mxx; i++){
        for(int j = 1; j <= n; j++)      //枚举每只牛
           if(!(i&(1 << j-1))){        //判断第j只牛是否在状态i中,不存在则进行计算
                   int nowf,nowg;      //当前f,g值
                  if(g[i] >= w[j]){      //如果原始最大剩余空间大于w[j]则说明可以将第j只牛装进去
                          nowg = g[i]-w[j];
                          nowf = f[i];
                  }
                  else nowg = c-w[j],nowf = f[i]+1;    //否则新用一个电梯
                  if(nowf < f[i | (1 << j-1)]){      //取原值与现值中的最小值
                          f[i | (1 << j-1)] = nowf;
                          g[i | (1 << j-1)] = nowg;
                  }
                  else if(nowf == f[i | (1 << j-1)])g[i | (1 << j-1)] = max(nowg,g[i | (1 << j-1)]);  //当nowf 与 f[i | (1 << j-1)]相等时,要更新g值最大,取更大那个
           }
    }
    if(g[mxx] < c)f[mxx]++;        //如果当前算得的最终状态剩下的容量小于c,则说明还需一个电梯
    printf("%d\n",f[mxx]);
    return 0;
}

 

posted @ 2017-10-19 21:59  君焰w  阅读(186)  评论(0编辑  收藏  举报