OJ题目 P1476 加工生产调度

题目描述

 算法思路分析

试着这样想 :由于每一个订单都需要A、B两个工厂合作完成,而且必须由A工厂先加工完成才能轮到B工厂对该订单进行加工,那么相当于A工厂是连续作业,即直到加工完最后一个订单为止,A工厂将会一直处于工作状态,而由于订单需要先经过A工厂的加工才能到B工厂进行加工,所以B工厂可能处于闲置状态,所以要使得加工完所有的订单的总时间最小,我们总是希望两台机器都尽量处于工作状态,不要有太多的闲置状态,A工厂不用说一直处于工作状态,关键点在于B工厂,B工厂可能处于闲置状态,所以我们希望B工厂尽可能多时间的处于工作状态,所以要让B工厂尽量处于工作状态,那么我们总是想要让在A工厂加工时间少而在B工厂加工时间多的订单先生产。

,所以理解大致思路之后,其实这类问题有一个固定的解法,即约翰逊(Johnson)算法,约翰逊算法的思路是这样的,先进性分组,将at[i]<bt[i],即在A工厂生产时间小于在B工厂生产时间的订单分为一组,记为M组,而at[i]>=bt[i],即在A工厂生产的时间大于等于在B工厂生产的时间的订单分成一组,记为N组,对于M组中的订单我们将其按照在A工厂生产的时间的长短进行升序排序,对于N组的订单我们将其按照在B工厂生产的时间的长短进行降序排序,最后订单的生产顺序就是,先生产M组中的第一个订单,再生产N组中的第一个订单,再生产M组中的第二个订单,再生产N足中的第二个订单,这样按照排序顺序,交替生产两组中的订单,此时生产顺序就是使得生产总时间最短的最优生产顺序。

理解算法思路之后,我们需要一个函数来进行约翰逊算法中的分组

void sep_group(int* a, int* b,int n)
{
	for (int i = 0; i < n; i++)
	{
		if (a[i] < b[i])
		{
			sg_a1[a1] = a[i];
			sg_b1[a1] = b[i];
			a1++;
		}
		else
		{
			sg_a2[a2] = a[i];
			sg_b2[a2] = b[i];
			a2++;
		}
	}

}

然后我们需要一个函数来实现约翰逊的算法进行求最短的加工生产时间,如

void GOrder(int* a, int* b, int n)
{
	//要让加工生产的总时间最短那么就要让两个生产车间都尽量处于工作状态,而不是一个车间在工作而另一个车间处于空闲状态,
	//那么可行的想法是尽可能让在车间B生产时间长的先进行处理,而且还要保证其在A车间生产的时间尽可能的短,这样的话就不会让B车间空闲的时间太多
	//而此题毫无疑问A车间将一直处于工作状态直到其将所有订单都生产完毕为止,而B车间有可能处于空闲状态
	//解决此题有一个固定的算法,就是约翰逊算法,
	//约翰逊算法的思路是,先进行分组,将在B车间生产的时间大于在A车间生产的时间的分为一组a1,而将在B车间生产的时间小于等于在A车间生产的时间的分为另一组a2
	//然后对于a1组我们按照在A车间生产的时间进行升序排序,对于a2组我们将其按照在B组生产的时间大小进行降序排序,然后根据排序后的两组顺序,
	//依次先取M组中的订单进行生产再选取N组中的订单进行生产,交替顺序选取,所得的订单生产顺序即为使得加工完所有订单时间最小的最优生产顺序。
	
	
	//将a1组按照在A车间生产时间的长短进升序排序
	int temp;
	for (int i = 0; i < a1 - 1; i++)
	{
		for (int j = 0; j < a1 - 1 - i; j++)
		{
			if (sg_a1[j] > sg_a1[j + 1])
			{
				temp = sg_a1[j];
				sg_a1[j] = sg_a1[j + 1];
				sg_a1[j + 1] = temp;
				temp = sg_b1[j];
				sg_b1[j] = sg_b1[j + 1];
				sg_b1[j + 1] = temp;	
			}

		}
	}
	//将a2组按照在B车间生产的时间长短进行降序排序
	for (int i = 0; i < a2 - 1; i++)
	{
		for (int j = 0; j < a2 - 1 - i; j++)
		{
			if (sg_b2[j] < sg_b2[j + 1])
			{
				temp = sg_a2[j];
				sg_a2[j] = sg_a2[j + 1];
				sg_a2[j + 1] = temp;
				temp = sg_b2[j];
				sg_b2[j] = sg_b2[j + 1];
				sg_b2[j + 1] = temp;
			}
		}
	}
	//然后按这样的顺序加工订单,即先取a1组中的第一个订单进行生产,再取a2组中的第一个订单进行加工生产,
	//然后又去取a1组中的第二笔订单进行加工生产,又取a2组中的第二笔订单进行加工生产,依次交替的顺序选取

	//将原数组按照此顺序进行排序
	int flag1 = 0, flag2 = 0;
	for (int i = 0; i < n; i++)
	{
		if (i % 2 == 0 && flag1 < a1)  
		{
			at[i] = sg_a1[flag1];
			bt[i] = sg_b1[flag1];
			flag1++;	
		}
		else
		{
			at[i] = sg_a2[flag2];
			bt[i] = sg_b2[flag2];
			flag2++;
		}
	}

	//计算按照最优生产顺序进行订单生产所需要的总时间
	int ya = 0;
	for (int i = 0; i < n; i++)
	{
		ya = ya + at[i];
		if (i == 0)
		{
			total_time += at[i];
		}
		else
		{
			int mark = total_time - ya + a[i];
			total_time = total_time + max(at[i] - mark, bt[i - 1]);
		}
		if (i == n - 1)
		{
			total_time += bt[i];
		}
	}


	

	

}

对于约翰逊算法中的确定订单生产顺序的代码实现比较简单,这里不做过多说明,如下是约翰逊算法中确定订单生产顺序的代码:

//将a1组按照在A车间生产时间的长短进升序排序
	int temp;
	for (int i = 0; i < a1 - 1; i++)
	{
		for (int j = 0; j < a1 - 1 - i; j++)
		{
			if (sg_a1[j] > sg_a1[j + 1])
			{
				temp = sg_a1[j];
				sg_a1[j] = sg_a1[j + 1];
				sg_a1[j + 1] = temp;
				temp = sg_b1[j];
				sg_b1[j] = sg_b1[j + 1];
				sg_b1[j + 1] = temp;	
			}

		}
	}
	//将a2组按照在B车间生产的时间长短进行降序排序
	for (int i = 0; i < a2 - 1; i++)
	{
		for (int j = 0; j < a2 - 1 - i; j++)
		{
			if (sg_b2[j] < sg_b2[j + 1])
			{
				temp = sg_a2[j];
				sg_a2[j] = sg_a2[j + 1];
				sg_a2[j + 1] = temp;
				temp = sg_b2[j];
				sg_b2[j] = sg_b2[j + 1];
				sg_b2[j + 1] = temp;
			}
		}
	}
	//然后按这样的顺序加工订单,即先取a1组中的第一个订单进行生产,再取a2组中的第一个订单进行加工生产,
	//然后又去取a1组中的第二笔订单进行加工生产,又取a2组中的第二笔订单进行加工生产,依次交替的顺序选取

	//将原数组按照此顺序进行排序
	int flag1 = 0, flag2 = 0;
	for (int i = 0; i < n; i++)
	{
		if (i % 2 == 0 && flag1 < a1)  
		{
			at[i] = sg_a1[flag1];
			bt[i] = sg_b1[flag1];
			flag1++;	
		}
		else
		{
			at[i] = sg_a2[flag2];
			bt[i] = sg_b2[flag2];
			flag2++;
		}
	}

对于目前的代码中出现的变量不理解其具体含义的可以先翻到文章末尾处看我给出的完整代码示例,完整代码示例中给出了各个变量的含义

最后确定好生产订单的顺序之后就是计算所需的最短的总时间,这一步比较难理解我会画图尽量的让大家理解:

我觉得可能大家看我上面写的这个可能没有耐心继续看下去,最好的办法是自己动手画一画,理解了如何求最短时间之后再去写代码 ,如下是求最短时间的代码:

//计算按照最优生产顺序进行订单生产所需要的总时间
	int ya = 0;
	for (int i = 0; i < n; i++)
	{
		ya = ya + at[i];
		if (i == 0)
		{
			total_time += at[i];
		}
		else
		{
			int mark = total_time - ya + a[i];
			total_time = total_time + max(at[i] - mark, bt[i - 1]);
		}
		if (i == n - 1)
		{
			total_time += bt[i];
		}
	}

完整的程序源代码以及运行结果截图:

完整程序源代码:

//此题需要用到约翰逊算法来实现,用于本题实现的算法思路固定,所以此题的解题方法可以直接背,下次再遇到同样的题目直接套解题模板即可

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#define N 10000
int at[N], bt[N];
int sg_a1[N], sg_b1[N], sg_a2[N], sg_b2[N];
int a1 = 0, a2 = 0;          //a1和a2分别代表第一组和第二组中的元素个数
int total_time = 0;


//以下函数用于求两个整数中较大的一个
int max(int a, int b)
{
	if (a >= b)
		return a;
	else
		return b;
}
//以下函数用于进行约翰逊算法中的分组
void sep_group(int* a, int* b, int n);

//以下函数用于求解加工生产调度问题
void GOrder(int* a, int* b, int n);

int main()
{
	int n;
	while (scanf("%d", &n) != EOF)
	{
		a1 = 0, a2 = 0;          
		total_time = 0;

		
		for (int i = 0; i < n; i++)
		{
			scanf("%d", &at[i]);
		}
		for (int i = 0; i < n; i++)
		{
			scanf("%d", &bt[i]);
		}
		sep_group(at, bt, n);
		GOrder(at, bt, n);
		printf("%d\n", total_time);

	}

}


void sep_group(int* a, int* b,int n)
{
	for (int i = 0; i < n; i++)
	{
		if (a[i] < b[i])
		{
			sg_a1[a1] = a[i];
			sg_b1[a1] = b[i];
			a1++;
		}
		else
		{
			sg_a2[a2] = a[i];
			sg_b2[a2] = b[i];
			a2++;
		}
	}

}

void GOrder(int* a, int* b, int n)
{
	//要让加工生产的总时间最短那么就要让两个生产车间都尽量处于工作状态,而不是一个车间在工作而另一个车间处于空闲状态,
	//那么可行的想法是尽可能让在车间B生产时间长的先进行处理,而且还要保证其在A车间生产的时间尽可能的短,这样的话就不会让B车间空闲的时间太多
	//而此题毫无疑问A车间将一直处于工作状态直到其将所有订单都生产完毕为止,而B车间有可能处于空闲状态
	//解决此题有一个固定的算法,就是约翰逊算法,
	//约翰逊算法的思路是,先进行分组,将在B车间生产的时间大于在A车间生产的时间的分为一组a1,而将在B车间生产的时间小于等于在A车间生产的时间的分为另一组a2
	//然后对于a1组我们按照在A车间生产的时间进行升序排序,对于a2组我们将其按照在B组生产的时间大小进行降序排序,然后根据排序后的两组顺序,
	//依次先取M组中的订单进行生产再选取N组中的订单进行生产,交替顺序选取,所得的订单生产顺序即为使得加工完所有订单时间最小的最优生产顺序。
	
	
	//将a1组按照在A车间生产时间的长短进升序排序
	int temp;
	for (int i = 0; i < a1 - 1; i++)
	{
		for (int j = 0; j < a1 - 1 - i; j++)
		{
			if (sg_a1[j] > sg_a1[j + 1])
			{
				temp = sg_a1[j];
				sg_a1[j] = sg_a1[j + 1];
				sg_a1[j + 1] = temp;
				temp = sg_b1[j];
				sg_b1[j] = sg_b1[j + 1];
				sg_b1[j + 1] = temp;	
			}

		}
	}
	//将a2组按照在B车间生产的时间长短进行降序排序
	for (int i = 0; i < a2 - 1; i++)
	{
		for (int j = 0; j < a2 - 1 - i; j++)
		{
			if (sg_b2[j] < sg_b2[j + 1])
			{
				temp = sg_a2[j];
				sg_a2[j] = sg_a2[j + 1];
				sg_a2[j + 1] = temp;
				temp = sg_b2[j];
				sg_b2[j] = sg_b2[j + 1];
				sg_b2[j + 1] = temp;
			}
		}
	}
	//然后按这样的顺序加工订单,即先取a1组中的第一个订单进行生产,再取a2组中的第一个订单进行加工生产,
	//然后又去取a1组中的第二笔订单进行加工生产,又取a2组中的第二笔订单进行加工生产,依次交替的顺序选取

	//将原数组按照此顺序进行排序
	int flag1 = 0, flag2 = 0;
	for (int i = 0; i < n; i++)
	{
		if (i % 2 == 0 && flag1 < a1)  
		{
			at[i] = sg_a1[flag1];
			bt[i] = sg_b1[flag1];
			flag1++;	
		}
		else
		{
			at[i] = sg_a2[flag2];
			bt[i] = sg_b2[flag2];
			flag2++;
		}
	}

	//计算按照最优生产顺序进行订单生产所需要的总时间
	int ya = 0;
	for (int i = 0; i < n; i++)
	{
		ya = ya + at[i];
		if (i == 0)
		{
			total_time += at[i];
		}
		else
		{
			int mark = total_time - ya + a[i];
			total_time = total_time + max(at[i] - mark, bt[i - 1]);
		}
		if (i == n - 1)
		{
			total_time += bt[i];
		}
	}


	

	

}

运行结果截图:我觉得要把完整的实现代码的思路写出来好难,感觉自己写代码的时候是完全对这个点理解了的但是要把它讲清楚又很难,就真的只可意会不可言传,我只能详细到这个步骤了,我感觉你们应该看不懂,我写完之后都不知道自己写了一个什么玩意,看不懂的地方都可以私信问我,我看到之后都会回复,祝生活愉快,学习进步!

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值