【动态规划专练-状压DP】CodeForces 580D (1800)

D. Kefa and Dishes

范围比较小可以用二进制暴力枚举
限制条件:前后相邻的拿的物品有贡献,所以状态要记录最后一个拿的物品,记录所有物品的状态,暴力枚举物品状态,枚举前一个后一个物品

点击查看代码
#include <iostream>
#include <map>
#include <vector>
#include <algorithm>
#include <stack>
#include <cstdio>
#include <queue>
#include <set>
#include<sstream>
#include <cstring>
#include <cmath>
#include <bitset>
//#pragma GCC optimize(2);
#define IOS ios::sync_with_stdio(false);
#define mm(a, b) memset(a, b, sizeof(a))
const double PI = acos(-1.0);
typedef long long ll;
const int N = 1e5+5;
const int M = N*2;
const double eps =1e-8;
const ll mod =  998244353;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const double maxd = -1e9;
const int maxn = 500;
using namespace std;
typedef pair<string,int> PII;
int a[20];
int g[20][20];
ll f[20][1<<20];
//dp[i][j] 最后吃的是i,当前的状态j
// k上一次吃的是k ,上一状态q
//dp[i][j] = max(dp[i][j],dp[k][q]+a[i]+g[k][i]);
int main(){
    int n,m,k,xi,yi,ci;
    cin>>n>>m>>k;
    for(int i=0;i<n;i++)cin>>a[i];
    while(k--){
        cin>>xi>>yi>>ci;
        g[--xi][--yi] = ci;
    }
    ll ans = 0;
    memset(f,0,sizeof f);
    for(int j=0;j<(1<<n);j++){
        int sum  = 1;
        int t = j;
        while(t&(t-1)) t= t&(t-1),sum++;//统计吃了多少个
        for(int i=0;i<n;i++){
            if(j&(1<<i)){
                for(int k=0;k<n;k++){
                    if(j&(1<<k)){
                        int q = j - (1<<i);
                        f[i][j] = max(f[i][j],f[k][q]+a[i]+g[k][i]);
                    }
                }
            }
            if(sum == m) ans = max(ans,f[i][j]);
        }
    }
    cout<<ans<<endl;
    return 0;
}
posted @ 2021-09-26 11:58  qingyanng  阅读(30)  评论(0编辑  收藏  举报