手记

动态规划——雇佣员工(hdu1158)

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=1158


题目描述:

有一家公司要完成一个课题,该课题分为n个月完成。现在知道每个月至少需要多少人手才能完成这个阶段的任务。假如说我们要聘请一个员工,那么我们就要有一定的花费(第二行的第一个数字);假如说我们解雇一个员工,那么我们也有一定的花费(第二行的第三个数字)。当然员工也是要拿工资的,每个月拿一定量的工资(假如说某个员工不干活也是拿工资的,第二行第二个数字),问你完成这个课题,最小需要花费多少钱?
样例解释:
3  //一个课题分三个月解决
4 5 6  //分别为聘请一个员工的花费、一个员工的工资、一个员工被解雇的花费
10 9 11 //第一个月至少需要10个人,第二个月至少需要9个人,第三个月至少需要11个人
输出:
199
第一个月聘请10个员工,花费:10*4+10*5(工资+聘请的费用)=90
第二个月不聘请员工(当然我们也可以解雇一个员工,当然也可以完成该阶段的任务,但是不聘请员工的做法才能达到最优解,具体你可以自己再纸上算算),花费:10*5=50(工资)
第三个月聘请一个员工,花费:10*5+4+5=59(10个人的工资+新聘请员工的工资+招聘费用)
那么总花费就是:90+50+59=199 即为最优解。
 
解题思路:在某个月我们无法直接判断究竟该雇佣多少员工,如测试数据,所以我们要用dp的思路,把每个月雇佣不同人数的最优解全部记录下来

dp[i][j]表示对于第i个阶段,保留j个人(要完成当月的任务)所需要的最少花费。j小于等于整个课题需要员工的最大额度



#include <stdio.h>int fmax(int a,int b){return a>b?a:b;}int fmin(int a,int b){return a<b?a:b;}int main(){int C_Max_Man,C_Min_Man;int V_nBuy,V_nKeep,V_nFire;int i,j,k;int m;int V_nSumAsNow,V_nSumAsKeep,V_nSumAsChange;int V_nLast_ans;int a[13];int dp[13][150];while(scanf("%d",&m)!=EOF&&m){C_Max_Man=0;C_Min_Man=150;scanf("%d%d%d",&V_nBuy,&V_nKeep,&V_nFire);for(i=1;i<=m;i++){scanf("%d",&a[i]);C_Max_Man=fmax(a[i],C_Max_Man);C_Min_Man=fmin(a[i],C_Min_Man);}for(i=1;i<=m;i++)for(j=C_Min_Man;j<=C_Max_Man;j++){if(i==1)dp[i][j]=j*(V_nKeep+V_nBuy);else{V_nSumAsNow=V_nSumAsKeep=dp[i-1][j]+j*V_nKeep;for(k=C_Min_Man;k<=C_Max_Man;k++){if(k==j)V_nSumAsChange=V_nSumAsKeep;if(k>j)V_nSumAsChange=dp[i-1][k]+(k-j)*V_nFire+j*V_nKeep;if(k<j)V_nSumAsChange=dp[i-1][k]+(j-k)*V_nBuy+j*V_nKeep;V_nSumAsNow=fmin(V_nSumAsNow,V_nSumAsChange);}dp[i][j]=V_nSumAsNow;}if(j<a[i])dp[i][j]=99999999;}V_nLast_ans=dp[m][C_Min_Man];for(j=C_Min_Man+1;j<=C_Max_Man;j++)V_nLast_ans=fmin(V_nLast_ans,dp[m][j]);/*    for(i=1;i<=m;i++)    {    for(j=min;j<=max;j++)    printf("%d ",b[i][j]);    printf("\n");    }    */printf("%d\n",V_nLast_ans);}return 0;}


0人推荐
随时随地看视频
慕课网APP