首页 > 技术文章 > Codeforces ----- Kefa and Dishes [状压dp]

real-l 2018-03-18 22:06 原文

题目传送门:580D

 

题目大意:给你n道菜以及每道菜一个权值,k个条件,即第y道菜在第x道后马上吃有z的附加值,求从中取m道菜的最大权值

看到这道题,我们会想到去枚举,但是很显然这是会超时的,再一看数据范围,n只有18,那么我们就可以用状压去做了,dp数组也还是比较好定义的,dp[i][state]表示现在吃到第i道菜状态为state的最大权值,既然有k个限制条件我们就按每个菜去扩展,然后就是一个裸的状压dp了,记得要开long long

#include<iostream>
#include<cstdio>
#include<cmath>
#include<string>
#include<cstring>
#define in(i) (i=read())
using namespace std;
typedef long long lol;
lol read()
{
    lol ans=0,f=1;
    char i=getchar();
    while(i<'0'||i>'9')
    {
        if(i=='-') f=-1;
        i=getchar();
    }
    while(i>='0'&&i<='9')
    {
        ans=(ans<<1)+(ans<<3)+i-'0';
        i=getchar();
    }
    return ans*f;
}
lol dp[19][1<<18];
lol a[19],b[19][19];
lol n,m,k;
int main()
{
    lol ans=0;
    in(n);in(m);in(k);
    for(lol i=1;i<=n;i++) in(a[i]);
    for(lol i=1;i<=k;i++)
    {
        lol u,v,c;
        in(u);in(v);in(c);
        b[u][v]=c;
    }
    for(lol i=1;i<=n;i++) dp[i][1<<i-1]=a[i];
    for(lol i=0;i<(1<<n);i++)
    {
        lol cnt=0;
        for(lol j=1;j<=n;j++)
        {
            if(i&(1<<(j-1)))
            {
                cnt++;//这里的cnt是已经经过前面的if的语句,也就是说这里的cnt是看此状态有多少位是1,也就是会吃多少道菜,所以才有了下面的if(cnt==m)这个语句
                for(lol k=1;k<=n;k++)
                {
                    if(!(i&(1<<k-1)))
                    {
                        dp[k][i|(1<<k-1)]=max(dp[k][i|(1<<k-1)],dp[j][i]+a[k]+b[j][k]);
                    }
                }
            }
        }
        if(cnt==m)
        {
            for(lol j=1;j<=n;j++)
                if(i&(1<<(j-1)))//一定要记得判断
                    ans=max(ans,dp[j][i]);
        }
    }
    cout<<ans<<endl;
    return 0;
}

推荐阅读