状压DP题集

【状压DP】Codeforces - 580D Kefa and Dishes (状压DP+记忆化搜索)(经典)

题目大意:

有$n ( n \leq18 )$个菜,现在要挑选$m$道菜,每个菜有一个满意度$a_i$,还有$k$个关系,每个关系为 $a b c$,表示$a$在$b$之前吃的话,就会额外增加$c$的满意度,现在要你输出最大的满意度。

解题分析:
$n$的数据范围很小,很容易想到状压DP。

#include <bits/stdc++.h>
using namespace std;

#define REP(i,s,t) for(int i=s;i<=t;i++)
typedef long long ll;
int n,m,k;
ll a[25],dp[(1<<20)][25],mp[25][25];
//dp[i][j]表示上一个选的是j,然后选了i中二进制表示的所有物品之后所取得的最大价值
ll DP(int cur,int last){
    if(__builtin_popcount(cur)==m)return 0;            //判断是否已经选够m件物品
    if(dp[cur][last]!=-1)return dp[cur][last];
    ll ans=0;
    REP(i,0,n){
        if(cur&(1<<i))continue;          //选过这个数就跳过
        ans=max(ans,a[i]+mp[last][i]+DP(cur|(1<<i),i));
    }
    return dp[cur][last]=ans;
}
int main(){
    scanf("%d%d%d",&n,&m,&k);
    REP(i,0,n-1)scanf("%lld",&a[i]);
    while(k--){
        int a,b,c;scanf("%d%d%d",&a,&b,&c);
        mp[--a][--b]=c;
    }
    memset(dp,-1,sizeof(dp));
    printf("%lld\n",DP(0,20));       //20是随便取的,取不存在的即可
}
View Code

猜你喜欢

转载自www.cnblogs.com/00isok/p/11184838.html