【题目描述】
农夫约翰的奶牛(1≤n≤20),总是方便的标记为1……N,或许应该叫N项全能,因为有N个不同的事件(通常有10个事件)。
牛i有一个s_ij的技能水平(1<=s_ij<=1000),是牛i在参与项目j时会得到的分数。每头奶牛必须且只能参加一个项目,每个事件必须有一些牛参加。
所有奶牛总得分为他们参加项目事件中的技能水平和。然而,项目的裁判如果有深刻印象,可以给出奖励分。评委可以给出B种奖励分(1≤B≤20)。奖励分i有三部分:如果奶牛在前k_i事件(包括这些事件其他牛的分数)获得了至少p_i(1< = p_i<=40000)分,他们将获得额外的a_i(1<=a_i<=1000)分(前k项触发的奖励积分不算到前k项的分数和,但算到之后的分数和中)。
例如,让我们考虑n = 3头牛技能水平如下:
cow | ||||
event | 1 | 2 | 3 | |
1 | 5 | 1 | 7 | |
2 | 2 | 2 | 4 | |
3 | 4 | 2 | 1 |
【输入格式】
第1行为N和B;
接下来有B行(2--B+1),其中第i+1行为 K_i, P_i,A_i;
再接下来有N行(B+2--B+1+N),其中第B+N+j行表示 s_j1...s_jN. 。
【输出格式】
输出只有一行,即牛得到的最大分数,包括奖励分。
【样例输入】
3 1 2 7 6 5 1 7 2 2 4 4 2 1
【样例输出】
17
【提示】
输出解释:
牛1参与项目1,牛2参与项目3,牛3参与项目2。
考虑每头牛其实只能参加一个项目 那么每个项目都会被参加且仅参加一次
那么可以大力状压dp
记cnt(now)为now这个状态二进制的1的个数(也就是有多少头牛)
f[now]=max(f[now|(1<<(i-1))]+v[cnt(now)][i]);
if(f[now]>=前cnt(now)的奖励分)
f[now]+=奖励分
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn=(1<<20)+10;
int f[maxn];
int s[30],p[30],v[30];
int A[30][30];
inline int lowbit(int x){return x&(-x);
}
inline int coun(int x){int ans=0;while(x){ans++;x-=lowbit(x);}return ans;
}
int main(){freopen("deca.in","r",stdin);freopen("deca.out","w",stdout);int n,b;scanf("%d %d",&n,&b);for(int i=1;i<=b;i++)scanf("%d %d %d",&s[i],&p[i],&v[i]);for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)scanf("%d",&A[i][j]);int top=(1<<n)-1;for(int i=0;i<=top;i++){int kount=coun(i);for(int j=1;j<=n;j++)if(i&(1<<(j-1)))f[i]=max(f[i],f[i-(1<<(j-1))]+A[j][kount]);int tmp=0;for(int j=1;j<=b;j++)if(s[j]==kount&&f[i]>=p[j])tmp+=v[j];f[i]+=tmp;}printf("%d\n",f[top]);
return 0;
}