[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; }