【Usaco2014 Feb】Cow Decathlon

题意

FJ有N(1 <= N <= 20)头奶牛,编号1至N。FJ提供N种不同的技能供奶牛们学习,每头奶牛只能学习一门技能,每门技能都要有奶牛学习。 第i头奶牛学习第j门技能,FJ得到的分数S[i][j],1<=S[i][j]<=1000。此外还有B(1 <= B <= 20)个奖励,第i个奖励的格式是: Ki 、Pi 、Ai,表示的意义是:如果学习完前Ki门技能后的总得分(包括额外的奖励得分)不少于Pi,那么FJ还会得到额外的Ai分。那么FJ应该如何安排奶牛学习技能,才能使得最后的总得分最高?

样例

Sample Input
3 1
2 7 6
5 1 7
2 2 4
4 2 1

Sample Output
17

OUTPUT DETAILS:
Cow 1 will perform event 1, cow 3 will perform event 2, and cow 2 will
perform event 3.

奶牛1学习技能1,奶牛2学习技能3,奶牛3学习技能2。

分析

状压DP,把每头牛的使用情况用二进制压缩
f[i]表示状态为i(二进制)时,能得的最多分
把奖励用个结构体存一下,每次判断能否得奖励就行了
还有个很吊的函数叫__builtin_popcount,可以自己去查一下
看代码吧。

代码

//Problem:【Usaco2014 Feb】Cow Decathlon
//weiqiang he
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=20+2;
int n,b,s[maxn][maxn],l[maxn],r[maxn];
int f[1<<maxn];
void readin(int &ret)    //读入优化 
{
    ret=0;
    char c;
    while((c=getchar()),(c>'9'||c<'0'));
    do{
        (ret*=10)+=c-'0';
    }
    while((c=getchar()),(c<='9'&&c>='0'));
}
struct node{
    int k,p,a;
}t[maxn];
bool cmp1(node a,node b){return a.k<b.k;}
bool cmp2(node a,node b){return a.p<b.p;}
int main()
{
    for(int i=0;i<maxn;i++)  l[i]=r[i]=-1;    //初始化l和r 
    int i,j,k,p,a;
    readin(n);readin(b);
    for(i=0;i<b;i++)
    {
        readin(k);readin(p);readin(a);
        t[i].k=k;t[i].p=p;t[i].a=a;
    }
    for(i=1;i<=n;i++)
      for(j=1;j<=n;j++)
      {
        readin(a);
        s[i][j]=a;
      }
    sort(t,t+b,cmp1);
    for(i=0;i<b;i++)
    {
        j=i;
        while(i+1<=n&&t[i].k==t[i+1].k) i++;
        sort(t+j,t+i+1,cmp2);
        l[t[j].k]=j;
        r[t[j].k]=i;
    }
    int S=1<<n;
    for(i=1;i<S;i++)
    {
        k=__builtin_popcount(i);  //__builtin_popcount:统计该数二进制中有几个一 
        for(j=1;j<=n;j++)
        {
            if(i&1<<j-1)        //判断是否学过此技能
                f[i]=max(f[i],f[i-(1<<j-1)]+s[j][k]);
        }
        if(l[k]!=-1)
        {
            for(j=l[k];j<=r[k];j++)
              if(f[i]>=t[j].p)
                f[i]+=t[j].a;
              else 
                break;
        }
    }
    printf("%d\n",f[S-1]);
    return 0;
}

你可能感兴趣的:(dp,状压dp,Usaco2014)