动态规划解复制书本问题

本文探讨如何利用动态规划技术有效地解决一个关于复制书本的任务优化问题。通过建立数学模型,我们分析了如何在限制条件下最小化复制成本,从而提高工作效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#include <iostream>
using namespace std;

#define  max(a, b)  a>b?a:b
#define  min(a, b)  a>b?b:a
#define  INTMAX     0x7FFFFFFF

int main()
{
	/*复制书本问题:
	      假设有 m 本书,编号为 1,2 ... m. 想将这些书抄写一份,m 本书的页数可能不同分别
	  用 p1, p2 ... pm 来表示各书本的页数,现在有 k 个抄写员,( k <= m ), 每本书只能分配给
	  一个抄写员进行复制,并且抄写员所分配的书必须是连续的,例如书本 1,2,3,4. 可以把2,3或
	  2,3,4 分配出去,而不能分配 2,4。抄写工作是同时进行的,并且抄写员的速度是一样的。
	  试求 m 本书分配给 k 个抄写员来完成,所用时间最小。

	  例如:9 3  //  表示 9 本书,3 个抄写员。
	        1 2 3 4 5 6 7 8 9   // 每本书的页数。
	  所用最小时间为:17

	  动态规划解题:
	      该题中 m 本书是顺序排列的, k 个抄写员所选择的数也是连续的。不管以书的编号,还是
	  以抄写员的编号来作为参量划分阶段,都符合策略的最优化原理和无后效性。考虑到 k<=m ,以、
	  抄写员编号来划分会方便一些。

	      p[t] 表示第 t 本书的页数。
	      F[i][j] 表示前 i 个抄写员复制前 j 本书所用的最少时间。考察第 i 个人的抄写情况,设
	  前面 t 本书有前 i-1 人抄写,而第 t+1, t+2 ... j 本书由第 i 个人抄写。
	  状态转移方程如下:

	  F[i][j] = min { max { F[i-1][t], p[t+1] + p[t+2] + ... + p[j] } }  ( i-1 =< t < j )
	  并且 2 <= i <= k , i < j <= m 。
	  当 i >= j 有 F[i][j] = max { p[1 ... j] } ,即抄写员人数不小于书本数。

	  maxp[i] 表示前 i 本书最大的页数。
	*/
	freopen("in.txt", "r", stdin);

	int F[500][500];  // 在 500 以内可以用有效时间运行完
	int p[500];
	int maxp[500]; // 表示前 i 本书最大的页数。

	int i, j, m, n, t, ti, tmin = INTMAX, tmax = 0, sump = 0;
	cin>>m>>n; // 输入书本数 m 和抄写员人数 n 

	for(t = 1; t <= m; t++) // 输入 m 本书的页数
	{
		cin>>p[t];
		if( tmax < p[t] )
			tmax = p[t];

		maxp[t] = tmax; // 前 t 本书最大的页数。
		F[1][t] = p[t];
	}

	for(j = 2; j <= m; j++) // 一个抄写员抄写前 j 本书所用时间
	{
		F[1][j] += F[1][j-1];
	} 

	for(i = 2; i <= n; i++)
		for(j = 1; j <= m; j++)
		{
			if( i >= j ) // 抄写员人数足够
			{
				F[i][j] = maxp[j]; // F[i][j] = max { p[1 ... j] }
			}
			else // 抄写员人数小于书本数
			{
				// F[i][j] = min { max { F[i-1][t], p[t+1] + p[t+2] + ... + p[j] } }
				/*
				tmin = INTMAX;
				sump = 0;
				for(ti = i-1; ti <= j; ti++)  //  此处可以改进!当数据量达到 300 时,明显慢了
				{
					sump = 0;
					for(t = ti+1; t <= j; t++)
					{
						sump += p[t];
					}
					tmax = max( F[i-1][ti], sump );
					if( tmin > tmax )
						tmin = tmax;
				}*/
				 改进后的 sump 做一次计算就可以了// 数据量他到 500 左右才出现明显的慢//
				tmin = INTMAX;
				sump = 0;
				for(t = i; t <= j; t++)
				{
					sump += p[t];
				}

				for(ti = i-1; ti <= j; ti++) // 
				{
					tmax = max( F[i-1][ti], sump );
					if( tmin > tmax )
						tmin = tmax;

					sump -= p[ti+1];
				}
				

				F[i][j] = tmin; // 取最小值
			}
		}

	cout<<F[n][m]<<endl; // 输出 m 本书 n 个抄写员完成任务的最小时间

	return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值