[USACO FEB14]奶牛的十项全能

【题目描述】


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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值