题意:
一个人去点餐从n种点出m种。每一种菜都会有一个满意度,并且他制订了k个规则
,若a在b之前吃的话,会额外得到满意度。求出最大满意度。
思路:
由于问题的规模不大(1 ≤ m ≤ n ≤ 18, 0 ≤ k ≤ n * (n - 1)),所以很明显要用到状态转移
dp,若何用呢?想到需要一个状态st表示菜的选择状态,i表示以第i种菜为结尾的最大
值,则遍历st的每一种情况去求出dp[st][i].
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int MAXN = 1<<18;
typedef long long LL;
int n,m,k;
LL dp[MAXN+10][21];
int bom[30][30];
int a[30];
int Cnt(int st)
{
int res = 0;
for(int i = 0;i < n; i++) {
if(st&(1<<i))
res++;
}
return res;
}
int main()
{
//freopen("in.txt","r",stdin);
scanf("%d%d%d",&n,&m,&k);
for(int i = 0;i < n; i++)
scanf("%d",&a[i]);
for(int i = 0;i < k; i++) {
int s,e,v;
scanf("%d%d%d",&s,&e,&v);
s--,e--;
bom[s][e] = v;
}
int maxn = 1<<n;
LL ans = 0;
for(int st = 0;st < maxn; st++) {
for(int i = 0;i < n; i++) {
if(st&(1<<i)) {
int flag = false;
for(int j = 0;j < n; j++) {
if(j != i && st&(1<<j)) {
flag = true;
dp[st][i] = max(dp[st][i],dp[st^(1<<i)][j] + a[i] + bom[i][j]);
}
}
if(!flag) {
dp[st][i] = a[i];
}
}
if(Cnt(st) == m) {
ans = max(ans,dp[st][i]);
}
}
}
cout<<ans<<endl;
return 0;
}