codeforces 580D 状压DP

codeforces 580D


题意:

n i a i m 饭店里有n种菜,吃第i种菜带来a_i点满意度,你需要吃m种菜才能吃饱,吃的菜品不能重复。
k x i y i c i x i y i c i 给出k组x_i、y_i、c_i,表示先吃第x_i种菜,再吃第y_i种菜,可以额外带来c_i点满意度。
问吃饱后的最大满意度。


题解:

d p [ i ] [ j ] i j i 1 0 dp[i][j]表示i状态下最后一盘菜为j的满意度,其中二进制状态下的i的各位1和0代表吃与不吃。

  • i j 1 k 0 d p [ i ( 1 < < k 1 ) ] [ k ] = m a x ( d p [ i ( 1 < < k 1 ) ] [ k ] , d p [ i ] [ j ] + a [ k ] + v [ j ] [ k ] ) 若二进制状态下的i的第j位等于1,而第k位等于0,dp[i | (1<<k-1)][k] = max(dp[i | (1<<k-1)][k], dp[i][j]+a[k]+v[j][k])
  • 1 < < n i m 遍历1<<n种状态,若二进制状态下的i的各位之和等于m,则状态合法

#include <bits\stdc++.h>
using namespace std;
typedef long long ll;
ll a[20], v[20][20];
ll dp[1<<18][20];

int main() {
    int n, m, k, x, y;
    cin >> n >> m >> k;
    for(int i = 1 ; i <= n ; i++){
        cin >> a[i];
        dp[1<<(i-1)][i] = a[i];
    }
    ll c;
    for(int i = 1 ; i <= k ; i++){
        cin >> x >> y >> c;
        v[x][y] = c;
    }
    ll ans = 0;
    for(int i = 1 ; i < (1<<n) ; i++){
        for(int j = 1 ; j <= n ; j++){
            if(i & 1<<(j-1)){
                for(int k = 1 ; k <= n ; k++){
                    if(!(i & 1<<(k-1))){
                        dp[i | (1<<k-1)][k] = max(dp[i | (1<<k-1)][k], dp[i][j]+a[k]+v[j][k]);
                    }
                }
            }
        }
    }
    for(int i = 1 ; i < (1<<n) ; i++){
        if(__builtin_popcount(i) == m){
            for(int k = 1 ; k <= n ; k++){
                ans = max(ans, dp[i][k]);
            }
        }
    }
    cout << ans << endl;
    return 0; 
}

猜你喜欢

转载自blog.csdn.net/CSDN_PatrickStar/article/details/89843054