题目链接:
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;
}