当前位置: 代码迷 >> 综合 >> [USACO FEB14]奶牛的十项全能
  详细解决方案

[USACO FEB14]奶牛的十项全能

热度:22   发布时间:2024-01-09 05:20:52.0

【题目描述】


农夫约翰的奶牛(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;
}