题目:http://www.gdfzoj.com/oj/contest/270/problems/3
有n盘菜,每盘菜都有一个美味值。但是你只能选m盘菜。并且这些吃菜的顺序能影响总美味值。如果i当且仅当在j之前吃,那么会额外加一些美味值,这样的组合有k组。求选m盘菜吃能获得的最大的美味值。
Input
第一行为n,m,k
第二行n个整数ai(0<=ai<=10^9)代表每盘菜的美味值
接下来k行每行三个整数xi,yi,ci(1<=xi,yi<=n,xi!=yi,0<=ci<=10^9),代表在吃第yi盘菜前吃第xi盘菜会增加第yi盘菜ci的美味值,保证不会有相同的二元组(xi,yi)。
对于50%的数据,1<=n,m<=10
对于100%的数据,1<=n,m<=15
Output
一个整数输出最大的美味值
Sample Input
样例输入1
2 2 1
1 1
2 1 1
样例输入2
4 3 2
1 2 3 4
2 1 5
3 4 2
Sample Output
样例输出1
3
样例输出2
12
看到这数据范围可以考虑状压,则f的其中一维便是状态
对于这些前后关系,肯定要一维来记录当前状态的最后一盘菜。
so,f[s,i]:最后一盘菜为i的状态s的最大美味值。
公式其实不难推,重点是生成状态
我们要按1的个数从小到大生成,原本是用dfs,这次又限制条件,改良一下即可
void dfs(int state,int pos,int tot)
{
if (pos>n)
{
if (tot==0)
s[++tmp]=state;
return ;
}
dfs(state,pos+1,tot);
if (tot>0)
dfs(state+(1<<(pos-1)),pos+1,tot-1);
}
int main()
{
for (i=1;i<=m;i++)
dfs(0,1,i);
}
代码:
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxS=15;
long long f[(1<<15)+5][maxS+5];
int a[maxS+5],c[maxS+5][maxS+5],s[800000+5];
int n,m,k1,tmp=0;
void dfs(int state,int pos,int tot)
{
if (pos>n)
{
if (tot==0)
s[++tmp]=state;
return ;
}
dfs(state,pos+1,tot);
if (tot>0)
dfs(state+(1<<(pos-1)),pos+1,tot-1);
}
int main()
{
int i,x,y,z,j,k;
freopen("a.txt","r",stdin);
scanf("%d%d%d",&n,&m,&k1);
memset(c,0,sizeof(c));
memset(f,0,sizeof(f));
memset(s,0,sizeof(s));
memset(a,0,sizeof(a));
for (i=1;i<=n;i++)
scanf("%d",&a[i]);
for (i=1;i<=k1;i++)
{
scanf("%d%d%d",&x,&y,&z);
c[x][y]=z;
}
for (i=1;i<=m;i++)
dfs(0,1,i);
for (i=1;i<=n;i++)
f[(1<<(i-1))][i]=a[i];
for (i=1;i<=tmp;i++)
{
for (j=1;j<=n;j++)
{
if (((1<<(j-1))&s[i])==0)
continue;
for (k=1;k<=n;k++)
{
if (((1<<(k-1))&s[i])>0)
continue;
f[s[i]+(1<<(k-1))][k]=max(f[s[i]+(1<<(k-1))][k],f[s[i]][j]+a[k]+c[j][k]);
}
}
}
long long ans=0;
for (i=1;i<=tmp;i++)
for (j=1;j<=n;j++)
ans=max(ans,f[s[i]][j]);
printf("%lld\n",ans);
return 0;
}