HDU

题意:给你n个工作集合,给你T的时间去做它们。给你m和s,说明这个工作集合有m件事可以做,它们是s类的工作集合(s=0,1,2,s=0说明这m件事中最少得做一件,s=1说明这m件事中最多只能做一件,s=2说明这m件事你可以做也可以不做)。再给你ci和gi代表你做这件事要用ci的时间,能获得gi的快乐值。求在T的时间内你能获得的最大快乐值。

思路:分三类各自求即可。0的时候必须更新,1的时候最多更新一次,2的时候正常01背包。

#include<bits/stdc++.h>
#define s first
#define e second
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define rep2(i,a,b) for(int i=a;i>=b;i--)
#define ll long long
using namespace std;
const int maxn=110;
const int inf=1e9;
int dp[maxn],tmp[maxn],c[maxn],g[maxn],T,M;
void solve0() //at least
{
    rep(i,0,T) tmp[i]=-inf;
    rep(i,1,M)
      rep2(j,T,c[i]){
        tmp[j]=max(tmp[j],max(dp[j-c[i]]+g[i],tmp[j-c[i]]+g[i]));
    }
    rep(i,0,T) dp[i]=tmp[i];
}
void solve1() //at most
{
    rep(i,0,T) tmp[i]=dp[i];
    rep(i,1,M)
      rep2(j,T,c[i])
        dp[j]=max(tmp[j-c[i]]+g[i],dp[j]);
}
void solve2() //free
{
    rep(i,1,M)
      rep2(j,T,c[i])
        dp[j]=max(dp[j-c[i]]+g[i],dp[j]);
}
int main()
{
    int N,S,ans;
    while(~scanf("%d%d",&N,&T)){
        memset(dp,0,sizeof(dp));
        ans=-1;
        rep(i,1,N){
            scanf("%d%d",&M,&S);
            rep(j,1,M) scanf("%d%d",&c[j],&g[j]);
            if(S==0) solve0();
            if(S==1) solve1();
            if(S==2) solve2();
        }
        ans=max(ans,dp[T]);
        printf("%d
",ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/hua-dong/p/11184959.html