题目:
Employment Planning
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 5314 Accepted Submission(s): 2275
3 4 5 6 10 9 11 0
199
有一家公司要完成一个课题,该课题分为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[i][j]表示对于第i个阶段,保留j个人(要完成当月的任务)所需要的最少花费。但是我们怎么知道最多会有几个人会被保留呢?其实结果就是每个月需要聘请员工的最大值。
代码:
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <stack>
#include <queue>
#include <vector>
#include <algorithm>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
int dp[20][1000];//表示第几个月保留几个人所需的最小花费
int num[20];//当前月份需要几个人
int main()
{
int n;
while(scanf("%d",&n)&&n)
{
int a,b,c,maxx=0;//a,b,c分别表示聘请的的花费、每月的工资花费、开除一个人的花费
scanf("%d%d%d",&a,&b,&c);
for(int i=1; i<=n; i++)
{
scanf("%d",&num[i]);
maxx=max(maxx,num[i]);//找出人数的最大需求量
}
mem(dp,1);//注意这时候把dp初始化任意一个正值就行,这个正值虽然随机但是比1大
for(int i=num[1]; i<=maxx; i++)
dp[1][i]=a*i+b*i;//初始化第一个月保留的人数的月花费
for(int i=2; i<=n; i++)
for(int j=num[i]; j<=maxx; j++)
for(int k=0; k<=maxx; k++)
if(k<=j)//表示当前状态是由聘请了(j-k)个人得来的
dp[i][j]=min(dp[i][j],dp[i-1][k]+(j-k)*a+j*b);
else//表示当前状态是由解雇了(k-j)个人得来的
dp[i][j]=min(dp[i][j],dp[i-1][k]+(k-j)*c+j*b);
int ans=9999999;
for(int i=0; i<=maxx; i++)
ans=min(dp[n][i],ans);
printf("%d\n",ans);//寻找最小值
}
return 0;
}