http://codeforces.com/contest/580/problem/D
题意:
有个人去餐厅吃饭,现在有n个菜,但是他只需要m个菜,每个菜只吃一份,每份菜都有一个欢乐值。除此之外,还有一些规则,x,y,w代表的是如果x吃完后吃y,那么还能获得额外的w欢乐值。计算所能获得的最大欢乐值。
思路:
看到别人说要用状压dp来做,我才恍然大悟啊,感觉自己对于状压dp实在是太不敏感了。
d【i】【j】表示在当前i状态时最后一份吃的是j的最大欢乐值。
状态转移什么的请看代码吧。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<sstream>
#include<vector>
#include<stack>
#include<queue>
#include<cmath>
#include<map>
#include<set>
using namespace std;
typedef long long ll;
typedef pair<int,int> pll;
const int INF = 0x3f3f3f3f;
const int maxn = +; ll n, m, t;
ll val[maxn];
ll d[<<][maxn], r[maxn][maxn]; int main()
{
//freopen("in.txt","r",stdin);
while(~scanf("%lld%lld%lld",&n,&m,&t))
{
for(int i=;i<n;i++) scanf("%lld",&val[i]); memset(r,,sizeof(r));
for(int i=;i<t;i++)
{
int x,y; ll w;
scanf("%d%d%lld",&x,&y,&w);
x--; y--;
r[x][y]=w;
} memset(d,-,sizeof(d));
for(ll i=;i< n;i++)
{
d[<<i][i]=val[i];
} ll ans=; for(ll i=;i<(<<n);i++)
{
int cnt=;
ll tmp=i;
while(tmp) //计算出i状态已经吃了几份菜了
{
if(tmp&) cnt++;
tmp>>=;
} for(ll j=;j<n;j++)
{
if(cnt==m && (i&(<<j))) ans=max(ans,d[i][j]); //如果已经吃了m份菜,分别求最后吃的是j的时候的欢乐值,维护最大值
if(cnt==m || !(i&(<<j))) continue; //如果还没够m份,接下计算吃k时所能获得的最大欢乐值
for(ll k=;k<n;k++)
{
if(i&(<<k)) continue;
d[(<<k)|i][k]=max(d[(<<k)|i][k],d[i][j]+val[k]+r[j][k]);
}
}
}
printf("%lld\n", ans);
}
return ;
}