TOJ 2898


题目标题:

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 左右 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值