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

本文解析了一道关于动态规划的问题——HDU 1158,探讨了如何通过动态规划求解在给定条件下完成项目的最低成本,并提供了完整的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:

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



评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值