题目:http://codeforces.com/contest/580/problem/D
题意:有n种菜(每一种菜有一个满意值ai>=0),你准备吃m种,每种一次。但是如果你按某种规则吃两种菜的话会增加额外的满意值,比如规则(xi yi ci)就是你先吃第xi个菜,然后马上吃第yi个菜,那么你就会额外增加ci点满意值。有k个这样的规则,问你吃m种菜后的最大满意值是多少。
分析:定义dp[i][j],i是bitmask,第x位为1代表选了第x种菜,j代表最后一次选的菜的下标,dp[i][j]是当前状态为(bitmask,lastnum)的剩余状态的最优解。然后记忆化搜索就行了。与之前习惯性写的含义不一样,之前写的是到达当前状态所选物品的最优解,这样肯定会错,因为和已选物品的先后顺序有关,假如求出dp[b][l],下次在到达这个状态(b,l)就直接返回了先前的那个可能更差的解。
错误代码:
long long DFS(int bitmask,int lastnum,long long val)
{
int c=cal(bitmask);
if(c>=m)
{
if(val>ans)
ans=val;
return val;
}
if(dp[bitmask][lastnum]!=-1)
return dp[bitmask][lastnum];
long long ret=-1;
for(int i=0;i<n;i++)
{
if(bitmask&(1<<i))
continue ;
ret=max(ret,DFS(bitmask^(1<<i),i,val+v[i]+buf[lastnum][i]));
}
return dp[bitmask][lastnum]=ret;
}
ac代码:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
int n,m,k;
long long v[20],buf[20][20];
long long ans,dp[1<<19][20];
long long DFS(int bitmask,int lastnum,int p)
{
if(dp[bitmask][lastnum]!=-1)
return dp[bitmask][lastnum];
if(p==m)
return 0;
long long ret=0;
for(int i=0;i<n;i++)
{
if(bitmask&(1<<i))
continue ;
ret=max(ret,DFS(bitmask^(1<<i),i,p+1)+v[i]+buf[lastnum][i]);
}
return dp[bitmask][lastnum]=ret;
}
int main()
{
int i,j,x,y,vl;
scanf("%d%d%d",&n,&m,&k);
for(i=0;i<n;i++)
scanf("%lld",&v[i]);
memset(buf,0,sizeof(buf));
while(k--)
{
scanf("%d%d%d",&x,&y,&vl);
buf[x-1][y-1]=vl;
}
ans=-1;
memset(dp,-1,sizeof(dp));
printf("%lld\n",DFS(0,19,0));
return 0;
}