JSP中求关键路径算法及java实现

在JSP问题中,关键路径决定着车间作业的完工时间,通过引入基于关键路径的邻域规则,使邻域解大大减少,从而大大减少优化过程的复杂度。

关键块是关键路径中工序在同一台机器连续组成的工序集合。

已知:

int[][] o = new int[n][m];  //o代表工序,值为各工序编号,i为工件编号,j为该工件工序编号
int[][] u = new int[n][m];   //工件i的第j个工序是第几台机器
int[][] p = new int[n][m];   //工件i的第j个工序的处理时间
int[][] startTime = new int[n][m];  //startTime[][]存储第i个工件的第j个工序的开始时间
int[][] finishTime = new int[n][m]; //finished[][]存储第i个工件的第j个工序的完成时间

算法:

 Step 1: 根据最大完工时间,求得最大完工时间所在的工序编号,并将该工序编号加入到关键路径链表中,该工序表示为o

 Step 2: 求preJob(o), preMac(o)

 Step 3: 若preJob(o) != null && preMac(o) != null,取50%概率选择其一,将新的工序加入插入到关键路径链表,并将该工序表示为o

              否则若preJob(o) != null,将preJob(o)插入到关键路径链表,并将该工序表示为o

              否则若preMac(o) != null,将preMac(o)插入到关键路径链表,并将该工序表示为o

 Step 4: 判断当前关键工序的开始时间是否等于0,如果不是,转Step2, 否则结束

说明:preJob(o):工序o在本工件上的前一工序,且该工序的结束时间等于o的开工时间

           preMac(o):  工序o所在机器在o前面紧挨的工序,即该工序的结束时间等于o的开工时间
实现代码:

//接下来计算关键路径
//求得最大时间所在的工序编号
int maxIndex = 0;
for(int i = 0; i < n; ++i){
	if(finishTime[i][9] == maxTime){
		maxIndex = i * 10 + 9;
	}
}		

//将这个工序加入关键路径链表中
ArrayList<Integer> keyPath = new ArrayList<Integer>();
keyPath.add(0, maxIndex);

int index_i = maxIndex / n;
int index_j = maxIndex % m;

//开始递推寻找,直到首工序
while(startTime[index_i][index_j] != 0){
	int preJobIndex = -1;
	int preMacIndex = -1;
	if(index_j != 0 && finishTime[index_i][index_j - 1] ==
			startTime[index_i][index_j]){//存在前序工序,且结束时间等于当前工序的开始时间
		preJobIndex = index_i * 10 + index_j - 1;
	}
	for(int i = 0; i < n; ++i){
		int mac = u[index_i][index_j];
		int macOpe = indi.machines[mac].tasks.get(i);
		int macOpe_i = macOpe / n;
		int macOpe_j = macOpe % m;
		if(finishTime[macOpe_i][macOpe_j] == startTime[index_i][index_j]){
			//存在所在机器的前一工序
			preMacIndex = macOpe;
			break;
		}
	}
	if(preJobIndex != -1 && preMacIndex != -1){//同时存在取50%概率选择
		if(Math.random() >= 0.5){
			keyPath.add(0, preJobIndex);
			index_j -= 1;					
		}
		else{
			keyPath.add(0, preMacIndex);
			index_i = preMacIndex / n;
			index_j = preMacIndex % m;
		}
	}
	else if(preJobIndex != -1){//只存在符合要求的工件前序工序
		keyPath.add(0, preJobIndex);
		index_j -= 1;
	}
	else if(preMacIndex != -1){//只存在符合要求的机器前序工序
		keyPath.add(0, preMacIndex);
		index_i = preMacIndex / n;
		index_j = preMacIndex % m;
	}
}		
//接下来对关键路径的工序进行分块
//思路来源于文档倒排索引的Reduce实现
KPB = new ArrayList<KPBlock>();
int preMac = -1;
KPBlock kpblock = new KPBlock();

for(int i = 0; i < keyPath.size(); ++i){
	int curOpe = keyPath.get(i);
	int cur_i = curOpe / n;
	int cur_j = curOpe % m;
	int curMac = u[cur_i][cur_j];
	if(preMac != curMac && preMac != -1){
		KPB.add(kpblock);
		kpblock = new KPBlock();
	}
	preMac = curMac;
	kpblock.block.add(curOpe);
}
KPB.add(kpblock); //加上最后一块
 
 
 
class KPBlock{
	ArrayList<Integer> block = new ArrayList<Integer>();
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值