【CF580D】Kefa and Dishes

题目描述

kefa进入了一家餐厅,这家餐厅中有n个菜(0<n<=18),kefa对第i个菜的满意度为ai(0<=ai<=10^9),并且对于这n个菜有k个规则,如果kefa在吃完第xi个菜之后吃了第yi个菜(保证xi、yi不相等),那么会额外获得ci(0<=ci<=10^9)的满意度。kefa要吃m道任意的菜(0<m<=n),但是他希望自己吃菜的顺序得到的满意度最大,请你帮帮kefa吧!


输入

第一行是一个数n

第二行是n个数,第i个数表示kefa对第i道菜的满意度为ai

第三行到第k+2行每行有3个数:xi,yi,ci,表示如果kefa在吃完第xi道菜之后立刻吃了第yi道菜,则会额外获得ci的满意度

输出

一行一个数表示最大满意度


样例输入

4 3 2
1 2 3 4
2 1 5
3 4 2


样例输出

12


题解

状压dp。

设dp[ s ][ i ] 表示当前状态为 s,最后一个吃的菜是 i 获得的最大满意度。

#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long

const int maxn=18+5;
const int maxm=(1<<18)+5;

ll n,m,k,ad[maxn][maxn],a[maxn];
ll dp[maxm][maxn],cnt,ans;

template<typename T>void read(T& aa){
    char cc; ll ff;aa=0;cc=getchar();ff=1;
    while((cc<'0'||cc>'9')&&cc!='-') cc=getchar();
    if(cc=='-') ff=-1,cc=getchar();
    while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar();
    aa*=ff;
}

int count(int x){
    int ret=0;
    while(x){
        ret++;x&=x-1;
    }
    return ret;
}

int main(){
    read(n),read(m),read(k);
    for(int i=1;i<=n;i++){
        read(a[i]);
        dp[1<<i-1][i]=a[i];
    }
    for(int i=1;i<=k;i++){
        ll x,y,z;
        read(x),read(y),read(z);
        ad[x][y]=z;
    }
    for(int s=0;s<(1<<n);s++){
        for(int i=1;i<=n;i++){
            if(!(s&(1<<i-1))) continue;
            for(int j=1;j<=n;j++){
                if(j==i||!(s&(1<<j-1))) continue;
                dp[s][j]=max(dp[s][j],dp[s^(1<<j-1)][i]+a[j]+ad[i][j]);
            }
        }
    }
    for(int s=0;s<(1<<n);s++)
    if(count(s)==m){
        for(int i=1;i<=n;i++){
            if(!(s&(1<<i-1))) continue;
            ans=max(ans,dp[s][i]);
        }
    }
    cout<<ans<<endl;
    return 0;
}
原文地址:https://www.cnblogs.com/rlddd/p/9819058.html