HDU 1158 Employment Planning
又一次看题解。
万事开头难,我想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代码:
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 }