codeforces 580 D. Kefa and Dishes(状压dp)

题目链接:http://codeforces.com/contest/580

题意:给出n种菜只能选m样。而且不能重复,而且如果按照某种规则来选菜的话还有额外的加成。

规则就是严格在某样菜的上一个选指定的菜。最后问最大权值为多少。

 

题解:看数据n,m最大18化作二进制也就不超过2^18 = 262 144,所以可以考虑用一下状压dp,

dp[i][j],i表示状态,j表示当前选择的是那样菜。

 

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
typedef long long ll;
const int M = (1 << 18);
int a[20] , ve[20][20];
ll dp[M][19];

int main() {
    int n , m , k , u , v , w;
    scanf("%d%d%d" , &n , &m , &k);
    memset(ve , 0 , sizeof(ve));
    for(int i = 0 ; i < n ; i++) {
        scanf("%d" , &a[i]);
    }
    for(int i = 0 ; i < k ; i++) {
        scanf("%d%d%d" , &u , &v , &w);
        ve[u - 1][v - 1] = w;
    }
    memset(dp , -1 , sizeof(dp));
    for(int i = 0 ; i < n ; i++) {
        dp[(1 << i)][i] = (ll)a[i];
    }
    ll MAX = 0;
    for(int i = 0 ; i < (1 << n) ; i++) {
        int count = 0;
        int gg = i;
        while(gg) {
            count += gg % 2;
            gg /= 2;
        }
        for(int j = 0 ; j < n ; j++) {
            if(dp[i][j] != -1) {
                if(count == m) {
                    MAX = max(MAX , dp[i][j]);
                }
                for(int k = 0 ; k < n ; k++) {
                    if(!(i & (1 << k))) {
                        ll sum = 0;
                        sum += (ll)ve[j][k];
                        sum += (ll)a[k];
                        dp[i | (1 << k)][k] = max(dp[i | (1 << k)][k] , dp[i][j] + sum);
                    }
                }
            }
        }
    }
    printf("%I64d\n" , MAX);
    //cout << MAX << endl;
    return 0;
}
posted @ 2017-04-21 18:07  Gealo  阅读(215)  评论(0编辑  收藏  举报