AOJ-AHU-OJ-145 流水线作业调度问题

来源:互联网 发布:淘宝ebay代购流程 编辑:程序博客网 时间:2024/04/30 11:22
流水线作业调度问题
Time Limit: 1000 ms   Case Time Limit: 1000 ms   Memory Limit: 64 MB
Description
N个作业{1,2,………,n}要在由两台机器M1和M2组成的流水线上完成加工。每个作业加工的顺序都是先在M1上加工,然后在M2上加工。M1和M2加工作业i所需的时间分别为ai和bi,1≤i≤n。
流水作业高度问题要求确定这n个作业的最优加工顺序,使得从第一个作业在机器M1上开始加工,到最后一个作业在机器M2上加工完成所需的时间最少。

Input
输入包括若干测试用例,每个用例输入格式为:
第1行 一个整数代表任务数n,当为0时表示结束,或者输入到文件结束(EOF)
第2行至第n+1行每行2个整数,代表任务在M1,M2上所需要的时间

Output
输出一个整数,代表执行n个任务的最短时间

Sample Input
OriginalTransformed
11 20

Sample Output
OriginalTransformed

3

——————————————————————分割线——————————————————————

思路:这一题的难度还是相当不小的。首先是一个两道工序的流水线排序问题(“同顺序”排序问题)。用Johnson算法来解决两道工序的流水线排序相对比较简单易懂,而且可以得到最优解。Johnson算法的大致内容如下:

(1)从加工时间矩阵中找出最短的加工时间。 
(2)若最短的加工时间出现在M1上,则对应的工件尽可能往前排;若最短加工时间出现在M2上,则对应工件尽可能往后排。然后,从加工时间矩阵中划去已排序工件的加工时间。若最短加工时间有多个,则任挑一个。 
(3)若所有工件都已排序,停止。否则,转步骤(1)。  

加工时间矩阵即为所有工件分别在两道工序上加工所需时间。M1为工序1,M2为工序2(进入工序2之前,工序1必须完工)。Johnson算法之所以能求出最优解,是因为:1.所有工件没开始加工时,只能加工工序1,工序2不得不空着。2.我们只能利用工序2的加工过程尽量省去工序1的时间。3.最后一个工件的工序2加工时间无法省去。所以“第i个”最小值如果为工序1,尽早加工,“第i个”最小值如果为工序2,最晚加工。(i = 1……n)

完成排序之后,计算工时。工时的计算我是模拟出来的。我姑且称之为双线计时。

代码如下:

#include <stdio.h>int wk[10000], work[10000][3];int mini[3], n;//这里的最小值mini我开成了数组,分为三个部分。mini[0]保存的是最小值,mini[1]保存的是最小值类型(当前最小是工序1 or 工序2)mini[2]是任务号void Findmi(){    int i;    for(i = 0; i < n; i++){        if(!work[i][2]){//如果该工件还未进行排序,分别看它的工序1工序2耗时,最后找到所有耗时中最小的            if(work[i][0] < mini[0]){                mini[0] = work[i][0];                mini[1] = 0;                mini[2] = i;            }            if(work[i][1] < mini[0]){                mini[0] = work[i][1];                mini[1] = 1;                mini[2] = i;            }        }    }//经过了一轮for循环之后,mini[0]保存的就是第一次寻找最小值的结果,mini[1]记录的是该值为工序1还是工序2,mini[2]记录的是工件的任务号    work[mini[2]][2] = 1;//做已排序记录}int Time(){//这个工时计算,相当得……TAT还是看变量吧!    int i = 0, j = 0, k = 0, v = 0;//i表示用时统计,j表示循环条件,使用k和v用作双线计时标记,即计时器1和计时器2,我们可以画一张工时计算图理解它们    for(;j < n; j++){        i = k;//进入循环体,更新i为当前k所在位置,k代表上次工序1使用完毕后计时器1显示的时间        while(work[wk[j]][0]--)//该工件工序1未完成            i++;//在工序1上进行加工        k = i;//工序1加工完成,k标记此时i所在位置,它意味着必须要等到Machine 1空闲才能运作        if(v < k)  v = k;//注意,此处补丁很重要,在i更新为v所在位置之前,一定要确认v在k的后面        i = v;//更新i为当前v所在位置,v代表上次工序2使用完毕后计时器2显示的时间        while(work[wk[j]][1]--)//该工件工序2未完成            i++;//在工序2上进行加工        v = i;//工序2加工完成,v标记此时i所在位置,它意味着必须要等到Machine 2空闲才能运作    }    return i;}int main(){int i, k, g;int m;while(scanf("%d", &n) != EOF&&n){        m = n; //下面会在计算中使用到任务数,因此保存下来,用任务号给工件们做编号        for(i = 0; i < n; i++){            scanf("%d%d", work[i]+0, work[i]+1);//work[][0]保存工序1所花时间,work[][1]保存工序2所花时间        work[i][2] = 0;//work[][2]用来记录该工件是否已经排序,相当于将每个工件的工序1耗时、工序2耗时连锁起来        }        for(k = 0,g = n-1;m > 0; m--){//排序直到所有工件参与后截止            mini[0] = 100000000;            Findmi();//每次使用Findmi()函数之后,找到一个未参与排序的工件的最小值            if(!mini[1])//如果它是工序1的,就排到最前面,否则最后面                {wk[k] = mini[2];k++;}//wk数组,-_-b汗颜,这么多奇怪的数组哈!保存了排序后的工件编号            else                {wk[g] = mini[2];g--;}//一个k++,一个g--,判定条件用m,好一个两边夹!        }        printf("%d\n", Time());//打印最省时方案的耗时}return 0;}



0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 遇征地企业不搬怎么办 dnf账号改错名了怎么办 银行卡绑定的手机号码换了怎么办 支付宝手机号码换了怎么办 淘宝账号被注销了怎么办 注销淘宝号绑定的手机号怎么办 淘宝账号不小心注销了怎么办 淘宝旧密码忘了怎么办 淘宝登录原始密码忘记了怎么办 微信原始密码忘记了怎么办 优酷会员重复交费怎么办 微信解绑手机号密码忘了怎么办 闪银呼呼逾期5天怎么办 忘记淘宝账号和密码怎么办 蘑菇街账号忘了怎么办 台式电脑密码忘记了怎么办 单位社保登陆密码忘记了怎么办 12306的登录密码忘了怎么办 网银支付密码忘了怎么办 邮政网银密码忘了怎么办 12306新注册待核验怎么办 建行网银盾密码忘了怎么办 建行网银登陆密码忘了怎么办 建行网银密码忘了怎么办 建行手机网银密码忘了怎么办 移动宽带账号密码忘了怎么办 移动宽带忘记账号密码怎么办 宽带账号密码忘了怎么办 不知道宽带账号密码怎么办 宽带的账号密码忘记了怎么办 wifi登录名忘记了怎么办 苹果手机微信图纸打不开怎么办 手机qq邮箱文件打不开怎么办 12360忘记用户名和密码怎么办 刚开店铺没生意怎么办 淘宝账户不符合注销条件怎么办 网易邮箱登录密码忘记了怎么办 q号密码忘记了怎么办 志愿者注册忘记密码和用户名怎么办 w10电脑语言栏不见了怎么办 w10美式键盘没了怎么办