Employment Planning (HDU 1158)

Employment Planning

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 3649    Accepted Submission(s): 1499


Problem Description
A project manager wants to determine the number of the workers needed in every month. He does know the minimal number of the workers needed in each month. When he hires or fires a worker, there will be some extra cost. Once a worker is hired, he will get the salary even if he is not working. The manager knows the costs of hiring a worker, firing a worker, and the salary of a worker. Then the manager will confront such a problem: how many workers he will hire or fire each month in order to keep the lowest total cost of the project.

Input
The input may contain several data sets. Each data set contains three lines. First line contains the months of the project planed to use which is no more than 12. The second line contains the cost of hiring a worker, the amount of the salary, the cost of firing a worker. The third line contains several numbers, which represent the minimal number of the workers needed each month. The input is terminated by line containing a single '0'.

Output
The output contains one line. The minimal total cost of the project.

Sample Input
  
  
3 4 5 6 10 9 11 0

Sample Output
  
  
199

Source

 

题意:

题意:给你一个n,然后给你3个数,分别代表雇佣费,薪水,解雇费,然后给你n个月的每月最低需要的人数,求最少花费费用。
刚开始我用贪心写的,但我以为自己写的是DP,结果WA。我非常不爽啊,怎么就不行呢,每次求出最小值后就能求最大值啊。。ca,纠结了一天。。后来发现我的思想是贪心啊!!靠。然后就不会写了==。看见别人都是用二维DP写的,我就想不通了,为什么一定要用二维的呢?反正MD就是不会写。于是看过n个人的文章后终有所悟,然后就水过了哭
 
思想:用一个二维的dp[i][j],i代表第几个月,j代表这个月所需人数,d[i][j]代表第i个月有j个人时从开始到现在共产生的最低费用。枚举每个月可能的雇佣人数,最小为num[i],最大为maxn(所有月份中最低所需人数的最大值)。于是本月与上个月就有两种关系(本月人数多的情况和少的情况),利用这种关系动态规划求出最小值(DP就是要这种重复的前后关系来进行递推)。第一个月直接是枚举可能性求出所需费用。
#include<cstdio>
#include<algorithm>
using namespace std;
const int INF = 1<<30;
int main()
{
    int n, i, j, k, hire, salary, fire, num[13], dp[13][105];

    while(~scanf("%d", &n), n)
    {
        scanf("%d%d%d", &hire,&salary,&fire);
        int maxn = 0;
        for(i=1; i<=n; i++)
        {
            scanf("%d", num+i);
            if(num[i] > maxn) maxn = num[i]; //求出最大需要人数
        }
        for(i=num[1]; i<=maxn; i++)
            dp[1][i] = (hire+salary)*i; //1月所需人数到最大人数这几种情况所需花费
        for(i=2; i<=n; i++)
        {
            for(j=num[i]; j<=maxn; j++)
            {
                int minn = INF;
                for(k=num[i-1]; k<=maxn; k++)
                {
                    if(j >= k) minn = min(minn, dp[i-1][k]+(j-k)*hire+j*salary);
                    else  minn = min(minn, dp[i-1][k]+(k-j)*fire+j*salary);
                }
                dp[i][j] = minn; //到第i个月的最小费用值
            }
        }
        int minn = INF;
        for(i=num[n]; i<=maxn; i++) //确定最后一个月的雇佣人数为多少时有最小值
            minn = min(minn, dp[n][i]);
        printf("%d\n", minn);
    }
    return 0;
}

也附上我一开始的WA代码。。
#include<cstdio>
int main()
{
    int n, i, j, hire, salary, fire, num[13], employee, dp;

    while(~scanf("%d", &n), n)
    {
        scanf("%d%d%d", &hire,&salary,&fire);
        for(i=1; i<=n; i++)
            scanf("%d", num+i);
        employee = num[1];
        dp = hire*num[1]+salary*num[1];
        for(i=2; i<=n; i++)
        {
            int minn = employee*salary, temp = employee;
            if(num[i] >= employee)
            {
                dp += (num[i]-employee)*hire+num[i]*salary;
                employee = num[i];
            }
            else
            {
                for(j=1; j<=employee-num[i]; j++)
                {
                    if(j*fire+(employee-j)*salary < minn)
                    {
                        minn = j*fire+(employee-j)*salary;
                        temp = employee-j;
                    }
                }
                employee = temp;
                dp += minn;
            }
        }
        printf("%d\n", dp);
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值