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

题意

给出n个物品,体积为w[i],现把其分成若干组,要求每组总体积<=W,问最小分组。(n<=18)

题解

一看以为是弱智题。(可能真的是,我太菜了)

然后跟walthou夸下海口:这么简单我做出来给你讲。

结果就被打脸了(对waithou说:我不会,自己看题解吧)

然后我就看了题解。。

设dp[i][j]为当前选i组已经选的情况为j的第i组的最小重量。

然后转移时,一个一个奶牛转移。

具体就是对于枚举的状态,如果dp[i][j]有不为INF,就枚举一个不属于j的x。

方程是

dp[i][j|(1<<x)]=min(dp[i][j|(1<<x)],dp[i][j]+a[x+1]);

dp[i+1][j|(1<<x)]=min(dp[i+1][j|(1<<x)],a[x+1]);

然后就没了(一开始18*218*218非用二次函数证明可以过,然后就A了一个点。

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<cmath>
 5 #include<algorithm>
 6 using namespace std;
 7 const int INF=999999999;
 8 int n,w;
 9 int a[20];
10 int dp[20][300000];
11 int main(){
12     scanf("%d%d",&n,&w);
13     int tot=(1<<n)-1;
14     for(int i=1;i<=n;i++){
15         scanf("%d",&a[i]);
16     }
17     for(int i=1;i<=n;i++)
18         for(int j=0;j<=tot;j++)
19             dp[i][j]=INF;
20     for(int i=0;i<=n-1;i++){
21         dp[1][1<<i]=a[i+1];
22     }
23     for(int i=1;i<=n;i++){
24         for(int j=0;j<=tot;j++)
25             for(int x=0;x<=n-1;x++)
26                 if(dp[i][j]!=INF){
27             //        cout<<i<<" "<<j<<" "<<dp[i][j]<<endl;
28                     if(((1<<x)&j)==0&&dp[i][j]+a[x+1]<=w)dp[i][j|(1<<x)]=min(dp[i][j|(1<<x)],dp[i][j]+a[x+1]);
29                     if(((1<<x)&j)==0)dp[i+1][j|(1<<x)]=min(dp[i+1][j|(1<<x)],a[x+1]);
30                 }
31     //    cout<<dp[i][tot]<<endl;
32         if(dp[i][tot]!=INF){
33             printf("%d",i);
34             return 0;
35         }
36     }
37     return 0;
38 }
View Code
原文地址:https://www.cnblogs.com/Xu-daxia/p/9396429.html