[JSOI2008]Blue Mary的职员分配

由于Blue Mary呕心沥血的管理,Blue Mary的网络公司蒸蒸日上。现在一共拥有了n名职员,可惜没有任何的金钱和声誉。平均每名每天职员都可以给公司带来x单位金钱或者y单位声誉(名利不能双全)。并且可以花费z单位的金钱在人才交易市场发布广告招聘职员,每次发布广告三天以后就会招聘到一名职员,并且必须在发布广告并且招聘到职员的那一天才能发布下一次广告。

Blue Mary计划以最快的时间获得至少A单位金钱和至少B单位声誉,请你计算一下他至少需要多少时间才能达到他的目标。

Solution

看着是个暴力dp,但要注意转移方向。

单纯获利是,从钱少的的地方向钱多的地方转移。

发广告时,从等待天数少的向天数多的地方转移,但钱会减少。

连续发广告是,从人少向人多转移,钱会减少。

我们的枚举顺序确定了,人,等待天数,钱,名誉。

Code

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int dp[41][21][21][4],n,x,y,z,a,b,ans;
int main(){
   scanf("%d%d%d%d%d%d",&n,&x,&y,&z,&a,&b);memset(dp,0x3f,sizeof(dp));
   dp[n][0][0][0]=0;
   ans=100;
   for(int i=n;i<=40;++i)
     for(int t=0;t<=3;++t)
     for(int j=0;j<=max(a,z);++j)
       for(int k=0;k<=b;++k)
         if(dp[i][j][k][t]<ans)
           {
               if(j>=a&&k>=b)ans=min(ans,dp[i][j][k][t]);
               for(int l=0;l<=i;++l){
                     int ma=min(j+l*x,max(a,z)),mb=min(k+(i-l)*y,b);
                     if(!t){
                           dp[i][ma][mb][0]=min(dp[i][ma][mb][0],dp[i][j][k][0]+1);
                           if(ma>=z)dp[i][ma-z][mb][1]=min(dp[i][ma-z][mb][1],dp[i][j][k][0]+1);
                     }
                    else if(t<3)
                      dp[i][ma][mb][t+1]=min(dp[i][ma][mb][t+1],dp[i][j][k][t]+1);
                    else {
                        dp[i+1][ma][mb][0]=min(dp[i+1][ma][mb][0],dp[i][j][k][t]+1);
                        dp[i+1][ma-z][mb][1]=min(dp[i+1][ma-z][mb][1],dp[i][j][k][t]+1);
                    }
               }
           }
        cout<<ans;
    return 0;
}
原文地址:https://www.cnblogs.com/ZH-comld/p/9549058.html