NAPIC 2016 C. Greetings! Scenes 状压DP

题目链接:http://codeforces.com/gym/101002

将容纳卡片的集合压缩后用j表示,dp【i】【j】用i个信封容纳集合j中的卡片。之后枚举j的子集,从i-1个信封中转移而来,最后输出dp【k】【(1<<n)-1】

 

另外今天学到了一种最快速遍历子集的方法%%%https://www.cnblogs.com/jffifa/archive/2012/01/16/2323999.html

#include<bits/stdc++.h>
#define inf 1e16
#define mod 1000000007
#define For(i,m,n) for(int i=m;i<=n;i++)
#define Dor(i,m,n) for(int i=m;i>=n;i--)
#define LL long long
#define lan(a,b) memset(a,b,sizeof(a))
#define sqr(a) a*a
using namespace std;

LL dp[20][32800];
LL a[20],b[20],c[20];
int main()
{
    int n,k;
    while(~scanf("%d%d",&n,&k))
    {
        for(int i=1;i<=n;i++)
            scanf("%lld%lld%lld",&a[i],&b[i],&c[i]);
            
            for(int i=1;i<=k;i++)
                for(int j=0;j<1<<n;j++)
                    dp[i][j]=inf;
            dp[0][0]=0;
            
            for(int i=0;i<=(1<<n)-1;i++)
            {
                LL maxa=0,maxb=0;
                LL num=0,sum=0;
                int tem=i;
                int id=1;
                while(tem)
                {
                    if(tem&1)
                        maxa=max(maxa,a[id]),maxb=max(maxb,b[id]),num+=c[id],sum+=c[id]*a[id]*b[id];
                    tem>>=1;
                    id++;
                }
                dp[1][i]=num*maxa*maxb-sum;
            }
        for(int i=2;i<=k;i++)
        {
            for(int j=0;j<=(1<<n)-1;j++)
            {
                for(int x=j;x;x=(x-1)&j)
                    for(int k=1;k<i;k++)
                        dp[i][j]=min(dp[i][j],dp[i-k][x]+dp[k][j-x]);//printf("dp %d %d=%lld\n",i,j,dp[i][j]);
            }
        }
        printf("%lld\n",dp[k][(1<<n)-1]);
    }
    return 0;

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值