HDU 1158 Employment Planning

Problem Description

A project managerwants to determine the number of the workers needed in every month. He doesknow the minimal number of the workers needed in each month. When he hires orfires a worker, there will be some extra cost. Once a worker is hired, he willget the salary even if he is not working. The manager knows the costs of hiringa worker, firing a worker, and the salary of a worker. Then the manager willconfront such a problem: how many workers he will hire or fire each month inorder to keep the lowest total cost of the project. 

 

 

Input

The input maycontain several data sets. Each data set contains three lines. First linecontains the months of the project planed to use which is no more than 12. Thesecond line contains the cost of hiring a worker, the amount of the salary, thecost of firing a worker. The third line contains several numbers, whichrepresent the minimal number of the workers needed each month. The input isterminated by line containing a single '0'.

 

 

Output

The outputcontains one line. The minimal total cost of the project.

 

 

Sample Input

3

4 5 6

10 9 11

0

 

 

Sample Output

199

 

感觉很暴力的一道题,dp[i][k]表示第i个月雇k个人时的当前所有花费的最小值。要算第dp[i][k]就要通过dp[i-1][j]得到。通过前一个月雇佣人数的情况,算出当前月雇佣k个人的情况,取其最小值。每个月雇佣人数应该是当月需要的最小值到所有月份最小值的最大值max1。

dp[i][k]的值有两种情况。如果dp[i-1][j]的j<k时,那么dp[i][k] = dp[i][j] + k*salary + (k-j)*hire_price;如果j>=k,那么dp[i][k] = dp[i][j] + k* salary  + (k-j)*fire_price。取这些值的最小值即为dp[i][k]的值。j的值从num[i-1]到max1,k的值从num[i]到max1。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;

int dp[13][1000010];//dp[i][j]表示第i个月雇j个人的最小值

int main()
{
	int month ,num[13];
	int hp ,fp ,as ,max1 ,min1;
	while(scanf("%d",&month),month)
	{
		scanf("%d%d%d",&hp,&as,&fp);
		max1 = 0;
		for(int i = 1;i<=month;i++)
		{
			scanf("%d",&num[i]);
			if(num[i] > max1)
			{
				max1 = num[i];
			}
		}
		for(int i = num[1];i <= max1;i++)
		{
			dp[1][i] = (hp + as) * i;
		}
		for(int i = 2;i <= month;i++)
		{
			for(int k = num[i];k <=max1;k++)
			{
				dp[i][k] = INT_MAX;
				for(int j = num[i-1];j <= max1;j++)
				{
					if(k >= j)
					{
						if(dp[i][k] > dp[i-1][j] + k * as + (k - j) * hp)
						{
							dp[i][k] = dp[i-1][j] + k * as + (k - j) * hp;
						}
					}
					else
					{
						if(dp[i][k] > dp[i-1][j] + k * as + (j - k) * fp)
						{
							dp[i][k] = dp[i-1][j] + k * as + (j - k) * fp;
						}
					}
				}
			}
		}
		min1 = INT_MAX;
		for(int i = num[month];i <= max1;i++)
		{
			if(min1 > dp[month][i])
			{
				min1 = dp[month][i];
			}
		}
		printf("%d\n",min1);
	}
	return 0;
}


 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值