CFGym 101002C 状压DP

题意

N种卡片,用K种格子去装。问浪费的空间。

题解

比赛的时候一直想的是斜率优化,然后成功TLE。看了别的队的代码才意识到是一个状压DP。
至于DP的方法,采用最暴力的方法就可以了。我们首先可以算出来任意一种长和宽的组合能包含哪几种卡片。然后可以暴力算出来任意一种长和宽的组合选择任意的卡片所需要的花费。最后DP,状态放在最外层,代表当前选择的卡片,格子数放在第二层,DP数组记录这两个状态就足够了。暴力对任意一种长和宽的组合所能包含的卡片进行状态转移。最后选择用0-K种盒子且包含所有状态,浪费最小的值就可以了。

注意事项

在进行状态转移的时候有一点小技巧,如果没注意到的话,会一直无法过样例。

int ss=c[j][p]|s;
dp[ss][i+1]=min(dp[ss][i+1],dp[s][i]+cost[ss^s][j][p]);

注意这里很有趣的一个去重小技巧。因为有可能当前的状态已经包含了新增状态的一部分。所以需要去重,已经有的状态不需要重复花费。

代码

#include <iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<string>
#include<set>
#include<map>
#include<bitset>
#include<stack>
#include<string>
#define UP(i,l,h) for(int i=l;i<h;i++)
#define DOWN(i,h,l) for(int i=h-1;i>=l;i--)
#define W(a) while(a)
#define MEM(a,b) memset(a,b,sizeof(a))
#define LL long long
#define INF 0x3f3f3f3f3f3f3f3f
#define MAXN 17
#define MOD 1000000007
#define EPS 1e-3
#define int LL
using namespace std;
int h[MAXN],w[MAXN],a[MAXN],x[MAXN],y[MAXN],dp[1<<MAXN][MAXN],cost[1<<MAXN][MAXN][MAXN],c[MAXN][MAXN];

main() {
    int n,k;
    scanf("%I64d%I64d",&n,&k);
    UP(i,0,n) {
        scanf("%I64d%I64d%I64d",&h[i],&w[i],&a[i]);
        x[i]=h[i];
        y[i]=w[i];
    }
    sort(x,x+n);
    sort(y,y+n);
    UP(i,0,n) {
        UP(j,0,n) {
            UP(p,0,n) {
                if(h[p]<=x[i]&&w[p]<=y[j]) c[i][j]|=(1<<p);
            }
        }
    }
    UP(i,0,n) {
        UP(j,0,n) {
            UP(s,0,1<<n) {
                UP(p,0,n) {
                    if(s&(1<<p)) cost[s][i][j]+=a[p]*(x[i]*y[j]-h[p]*w[p]);
                }
            }
        }
    }
    MEM(dp,INF);
    dp[0][0]=0;
    UP(s,0,1<<n) {
        UP(i,0,k) {
            if(dp[s][i]==INF) continue;
            UP(j,0,n) {
                UP(p,0,n) {
                    int ss=c[j][p]|s;
                    dp[ss][i+1]=min(dp[ss][i+1],dp[s][i]+cost[ss^s][j][p]);
//                    cout<<dp[s|c[j][p]][i+1]<<" "<<(s|c[j][p])<<endl;
                }
            }
        }
    }
    int ans=INF;
    UP(i,0,k+1) ans=min(ans,dp[(1<<n)-1][i]);
    printf("%I64d\n",ans);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值