题目标题:
Employment Planning
题目连接:
http://acm.tzc.edu.cn/acmhome/problemdetail.do?&method=showdetail&id=2898
题目类型:
动态规划
数据结构:
// month, worker
int dp[15][MAXPLE];
思路分析:
给定每个月最低工作人数,
决定雇佣或者裁员或者保持原样
使得总支出最小
典型的动态规划问题
关键是以每个月为一个决策节点
对当月的不同人数对比上个月的各种情况人数施以计算,
当月每个人数都保留最优有效解
则最后一个月的最少支出为答案..
比如 第一个月 对最少人数至最多人数计算 保留各个值
第二个月 最低人数9个人的情况 对 一月份各个人数情况计算 取最小值
再10个人的情况 对上一个月再执行重复的步骤 保留当月最小值
证明:
1. 所有雇员行为都是越迟越好, 至少不会得到更差的解
此思路建立在每个月都是对前几个月独立的情况上
每个月相当于都是新的决策点 不受过去情况的影响.
源代码:
#include <iostream>
#include <stdio.h>
using namespace std;
#define MAXPLE 205
// month, worker
int dp[15][MAXPLE];
int main()
{
int i, j, k, maxples;
int months;
int hiring, salary, firing;
int arr[13];
while( scanf( "%d", &months ), months )
{
maxples = -1;
memset( arr, 0, sizeof( arr ) );
memset( dp, 0, sizeof( dp ) );
scanf( "%d%d%d", &hiring, &salary, &firing );
for( i = 1; i <= months; i ++ )
{
scanf( "%d", arr + i );
if( arr[i] > maxples )
{
maxples = arr[i];
}
}
for( i = arr[1]; i <= maxples; i ++ )
{
dp[1][i] = hiring * i + salary * i;
}
for( i = 2; i <= months; i ++ )
{
for( j = arr[i]; j <= maxples; j ++ )
{
int tmp = 0, min = INT_MAX;
for( k = arr[i - 1]; k <= maxples; k ++ )
{
if( dp[i - 1][k] )
{
tmp = dp[i - 1][k] + j * salary + ( j > k ? ( j - k ) * hiring : ( k - j ) * firing );
if( tmp < min )
{
min = tmp;
}
}
}
dp[i][j] = min;
}
}
int m = INT_MAX;
for( i = arr[months]; i <= maxples; i ++ )
{
if( dp[months][i] < m )
{
m = dp[months][i];
}
}
printf( "%d\n", m );
}
return 0;
}
优化:
只需对所有月份中最大人数的那个当上界即可
没有必要对所有可能的人数求解
在 HDOJ 15MS 在 TOJ 500MS 左右