NAPIC 2016 C. Greetings! Scenes 状压DP

版权声明:本文为博主原创文章,转载请附上原博客链接。 https://blog.csdn.net/Dale_zero/article/details/82928319

题目链接: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;

}

猜你喜欢

转载自blog.csdn.net/Dale_zero/article/details/82928319
今日推荐