[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; }