又一次看题解。

万事开头难,我想DP也是这样的。

呵呵,不过还是有进步的。

比如说我一开始也是打算用dp[i][j]表示第i个月份雇j个员工的最低花费,不过后面的思路就完全错了。。

不过这里还有个问题,这样开数组j开多大比较好,难道要我开2^31-1这么大?

题解里面开了1000多,也许再小一点也能过吧。

 

因为有可能解雇一个人的花费比较大,所以某个月可能继续雇佣他这样总的算来是最省的。

所以第i个月可能雇佣的人数是从num[i] ~ NumMax。

首先对第一个月的费用初始化,就是(雇佣+薪水)×人数。

后面便是核心代码,

1 if(j < num[i - 1])
2                     dp[i][j] = dp[i - 1][num[i - 1]] + salary * j + (num[i - 1] - j) * fire;
3                 else
4                     dp[i][j] = dp[i - 1][num[i - 1]] + salary * j + (j - num[i - 1]) * hire;

这一句是为了后面的状态转移做准备,

先假设在上个月恰好雇num[i - 1]人的最小费用的基础上,人数多了就解雇,少了就雇佣是最省的。

然后再增加一个循环变量k,假如上个月多雇了一个人,那么这个月不用解雇也许可能更省。

1 for(int k = num[i - 1] + 1; k <= NumMax; ++k)
2                 {
3                     if(k > j)
4                         dp[i][j] = min(dp[i][j], dp[i - 1][k] + j * salary + (k - j) * fire);
5                     else
6                         dp[i][j] = min(dp[i][j], dp[i - 1][k] + j * salary + (j - k) * hire);
7                 }

最后就是输出最优解了,最优解有可能在数组最后一行的任何一个地方(还是那句话,假如上个月多雇了一个人,那么这个月不用解雇也许可能更省。)

所以要找到最后一行的最小值来输出。

总结:

注意:千万不要的在心情不平稳的时候敲代码,这样只会越敲越乱,与其去改还不如心平气和的从头开始敲,好有个完整的思路。

刚才9点多在教室里是时候因为要快熄灯了,而且这一天就在搞这一道题,还没完全弄明白。便有些心急,想着今天怎么也要把这道题

A出来。结果回宿舍改的时候各种错误,变量名打错,不等号搞反之类的。

不管是做题还是敲代码,平心静气,切记切记!

完整的AC代码:

HDU 1158 Employment Planning_数组HDU 1158 Employment Planning_数组_02
 1 #define LOCAL
 2 #include <iostream>
 3 #include <cstdio>
 4 #include <cstring>
 5 #include <algorithm>
 6 using namespace std;
 7 
 8 int dp[15][1200];
 9 int num[15];
10 
11 int main(void)
12 {
13     #ifdef LOCAL
14         freopen("1158in.txt", "r", stdin);
15     #endif
16 
17     int n;
18     while(scanf("%d", &n) && n)
19     {
20         int i;
21         int fire, salary, hire;
22         int NumMax = 0;
23         scanf("%d %d %d", &hire, &salary, &fire);
24         
25         for(i = 0; i < n; ++i)
26         {
27             scanf("%d", &num[i]);
28             if(NumMax < num[i])
29                 NumMax = num[i];
30         }
31         if(NumMax == 0)
32         {
33             printf("0\n");
34             continue;
35         }
36         for(i = num[0]; i <= NumMax; ++i)
37             dp[0][i] = i * (hire + salary);
38 
39         for(i = 1; i < n; ++i)
40         {
41             for(int j = num[i]; j <= NumMax; ++j)
42             {
43                 if(j < num[i - 1])
44                     dp[i][j] = dp[i - 1][num[i - 1]] + salary * j + (num[i - 1] - j) * fire;
45                 else
46                     dp[i][j] = dp[i - 1][num[i - 1]] + salary * j + (j - num[i - 1]) * hire;
47             
48                 //考虑到与其解雇一个人还不如让他继续待下去的情况
49                 for(int k = num[i - 1] + 1; k <= NumMax; ++k)
50                 {
51                     if(k > j)
52                         dp[i][j] = min(dp[i][j], dp[i - 1][k] + j * salary + (k - j) * fire);
53                     else
54                         dp[i][j] = min(dp[i][j], dp[i - 1][k] + j * salary + (j - k) * hire);
55                 }
56             }
57         }
58 
59         int ans = 2000000000;
60         for(i = num[i - 1]; i <= NumMax; ++i)
61             ans = min(dp[n - 1][i], ans);
62         printf("%d\n", ans);
63     }
64     return 0;
65 }
代码君