hdu1158【DP】
题意:
第一行项目数;
第二行每个工人的Hire Salary Fire money
第三行每个项目需要的人的数量;
工人在hire/fire的时候要付出额外的钱,如果已经hire了还没有fire就一直会付salary求一个最小开支。
思路:
这题因为感觉就是DP,所以也没想贪心。。
H:hire的钱
S:salary
F:firep[]代表项目人数;
首先可以看出:
①:p[i-1]<p[i] :要再雇几个人,前一状态+H*(p[i]-p[i-1])+S*p[i]
②:p[i-1]==p[i] :直接就是 前一状态+S*p[i]
③:p[i-1]>p[i] :要先去几个人,前一状态+F*(p[i]-p[i-1])+S*p[i]
用dp[i][j]代表前i个项目的j个人的消费;
从前一状态到后一状态的改变:我们可以想到最多最多雇的人不会超过期间最多的人;
所以对于每次状态的更新都要更新到最多人次,而每次人次的下界,并不是最小,因为对于第i个项目你最小要拿p[i]个人,所以每次状态的更新是从p[i]到会出现的最多人次;
然后转移过来的值,就是在之前的状态经过转换后的一个最小值,而前一状态有:dp[i-1][j],p[i-1]<=j<=tmax(某项目最多人)
那么初始化,状态转移就不难了~
#include<bits/stdc++.h> using namespace std; typedef long long LL; const int N=12+10; const int INF=0x3f3f3f3f; int p[N]; int dp[N][1010]; int H; int S; int F; int n; int main() { int n; while(~scanf("%d",&n)&&n) { scanf("%d%d%d",&H,&S,&F); scanf("%d",&p[1]); int tmax=p[1]; for(int i=2;i<=n;i++) { scanf("%d",&p[i]); tmax=max(p[i],tmax); } memset(dp,0,sizeof(dp)); for(int i=p[1];i<=tmax;i++) dp[1][i]=i*S+i*H; int temp; for(int i=2;i<=n;i++) { for(int j=p[i];j<=tmax;j++)//对于第i次的更新; { temp=INF; for(int k=p[i-1];k<=tmax;k++)//从前一状态拿一个最小值; if(temp>dp[i-1][k]+(j>=k?(j*S+(j-k)*H):(j*S+(k-j)*F))) temp=dp[i-1][k]+(j>=k?(j*S+(j-k)*H):(j*S+(k-j)*F)); dp[i][j]=temp; } } int ans=dp[n][p[n]]; for(int i=p[n]+1;i<=tmax;i++) ans=min(ans,dp[n][i]); printf("%d\n",ans); } return 0; }