C++ 复制书稿

【问题描述】

假设有n个任务由k个可并行工作的机器完成。完成任务i需要的时间为ti。试设计一个算法找出完成这n个任务的最佳调度,使得完成全部任务的时间最早。

现在要求分配给一个机器的任务必须是连续的,比如不能把1、3、4号任务分配给同一个机器。

现在请你设计一种方案,使得完成所有任务的时间最短。完成任务的时间取决于耗时最长的那台机器。

【输入】

第一行两个整数n,k;

第二行n个整数,第i个整数表示第i个任务所需要的时间ti。

【输出】

共k行,每行两个整数,第i行表示第i个机器分配的任务的起始编号和终止编号。K行的起始编号应该从小到达排列,如果有多解,则尽可能让前面的人少抄写。

【输入输出样例】

machine.in

machine.out

9 3

1 2 3 4 5 6 7 8 9

1 5

6 7

8 9

【数据范围】

对于20%的数据,n≤50。

对于100%的数据,k≤n≤500。

本题可以使用动态规划解决,设f(i,j)为当前j本书交由i个人抄写,需要的最短时间,则动态转移方程为 f(i,j)=max(f[i-1][1],d[j]-d[1]);

动态规划求出的仅仅是最优质,如果要输出具体方案,还需要根据动态规划计算的最优质,做一个贪心设计。具体来说,设最优质为T,那么k个人,每个人抄写最多T页。从最后后一本书开始按逆序将数分配给k个人去抄写,从第k个人开始,如果他还能写,就给他;

否则第k个人的工作分配完毕,开始分配第k-1个人的工作;以后再是k-2个、k-3个......直至第一个。一遍贪心后,具体的方案就出来了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
using namespace std;
int maxl(int,int);
int print(int,int);
int x,y,m,n,k,t,l;
int a[600],f[600][600],d[600];
int main()
{
	cin>>m>>k;
	for(int i=0;i<=500;i++)
	for(int j=0;j<=500;j++)
	f[i][j+]=1000000;
	for(int i=1;i<=m;i++)
	{
		cin>>a[i];
		d[i]=d[i-1]+a[i];//前缀和
		f[1][i]=d[i];//f[1][j]为一个人抄前j本书所需的时间
	}
	for(int i=2;i<=k;i++)//f[k][m]为当前m本书交由k个人抄写,需要的最短时间。
	for(int j=1;j<=m;j++)
	for(l=1;l<=j-1;l++)
		if(maxl(f[i-1][l],d[j]-d[l])<f[i][j])
		f[i][j]=maxl(f[i-1][l],d[j]-d[l]);
	print(m,k);//从第k个开始分配抄写方案
}
int maxl(int x,int y)//求最大值,和max的用处一样
{
	if(x>y)return x;else return y;
}
int print(int i,int j)//递归输出抄写方案
{
	int t,x;
	if(j==0)return 0;
	if(j==1)//第一个人抄写1到i本书
	{
		cout<<1<<" "<<i<<endl;
		return 0; 
	}
	t=i;x=a[i];
	while(x+a[t-1]<=f[k][m])
        //从最后一本书按逆序分配第j个人抄写,只要能写,就给他
	{
		x+=a[t-1];
		t--;
	}
	print(t-1,j-1);
       //用递归过程给第j-1个人分配抄写方案,这是只有t-1本书了
	cout<<t<<" "<<i<<endl; 
      //递归返回时输出,因为递归过程是最后1个人先分配抄书
}

  

猜你喜欢

转载自www.cnblogs.com/FXY-180/p/9509970.html
今日推荐