分配问题-分支限界法

// branchBound_assignJob.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"

#include <iostream>
#include <cstring>
#include <vector>
using namespace std;

#define  N 4

//case 1 --> N=5
//int c[][N]={
//	3,  8,  4, 12,16,
//	9, 12, 13,  5,12,
//	8,  7,  9,  3,10,
//	12, 7,  6,  8,11,
//	23, 17, 26, 18, 13
//};

//case 2 --> N=4
int c[][N]={
	3,  8,  4, 12,
	9, 12, 13,  5,
	8,  7,  9,  3,
	12, 7,  6,  8
};


//case 3 --> N=3
//int c[][N]={
//	4, 3, 2,
//	2, 4, 6,
//	8, 7, 5
//};


int costBoundInK = 65535;//搜索深度为k时的花费下界,深度为k有N-k个节点的下界,取最小值给minCostInk
int minCostInk = 65535;//搜索深度为k时的最小下界
int minCostLine = 0;//记录最小下界节点所在的行
int expanded[N];//存放被扩展节点的顺序
vector<int> vectors;//存放搜索深度为k时的花费下界,即costBoundInK

int min_exceptiInRow(int i,int row)
{
	int min = 65535;
	for (int line=0; line<N; line++)
	{
		bool currExpanded =false;
		for (int m=0;m<N;m++)
		{
			if (expanded[m] == line)//line行的某一节点已经之前被扩展过,故这一行的节点不能再扩展
			{
				currExpanded = true;
				break;
			}
		}
		//功能:除去当前行和之前被扩展的节点所在行之后,通过循环找出row这列的最小值
		if (line!=i  && !currExpanded && c[line][row]<min)//与i不在同一行,同时节点未被扩展,且是这一列中的最小值
		{
			min = c[line][row];
		}
	}
	return min;
}

/************************************************************************
**功能:求出最小的花费
**参数:k为作业编号
		mincost为最终返回的最小花费
************************************************************************/
void branchBound(int k,int& mincost)
{
	while(true)
	{
		if (k<N)//未到叶子节点
		{
			bool currExpanded = false;
			minCostInk = 65535;
			for (int i=0; i<N; i++)
			{
				for (int m=0;m<N;m++)
				{
					if (expanded[m]==i)//查看当前行的某一节点是否已经被扩展过,若扩展过,则当前行的所有节点都不能再扩展
					{
						currExpanded = true;
						break;
					}
				}
				if (!currExpanded)//当前行未被扩展
				{
					costBoundInK = c[i][k];//costBoundInK表示在某个搜索深度k下,把作业k分配给工人i时的时间下界
					for (int j=k+1;j<N;j++)
					{
						costBoundInK += min_exceptiInRow(i,j);//深度k下的花费下界,即在未扩展节点所在列均取花费的最小值,并累加
					}
					if (costBoundInK < minCostInk)
					{						
						minCostInk = costBoundInK;
						minCostLine = i;		//记录要扩展节点的行号
						expanded[k] = i;		//expanded[k]记录花费矩阵中节点被扩展的顺序,k为列,代表作业编号,依次为0,1...N
												//对应的i为行,代表工人编号,即分配方案为工人i完成作业k
					}
					vectors.push_back(costBoundInK);//不同深度k下计算的花费下界存入vectors容器;深度为k时,需要计算N-k次下界,取最小值为扩展节点
				}
				currExpanded = false;
				expanded[k]=-1;//同级节点扩展,恢复当前节点为未扩展
			}
			expanded[k] = minCostLine;//选取当前搜索深度k下,花费最少的为扩展节点c[minCostLine][k]
			k++;
		}
		else//到达叶节点
		{
			for(int i=0;i<N;i++)//根据扩展节点的顺序,计算最小花费
			{
				mincost +=c[expanded[i]][i];
			}
			break;
		}
	}
}

int main(int argc, char *argv[])
{
	memset(expanded, -1, N*sizeof(int));//给数组置-1

	int mincost=0;
	branchBound(0,mincost);//分支限界算法,从根节点开始扩展,由mincost返回最少花费


	//输出
	cout<<"-------花费矩阵(行为工人,列为作业,从0开始)----------"<<endl;
	for (int i=0;i<N;i++)
	{
		for (int j=0;j<N;j++)
		{
			printf("%3d ",c[i][j]);	
		}
		cout << endl;
	}
	cout<<"---------------------------------------------"<<endl;

	for(int i=0;i<N;i++)
	{
		cout<< "作业:" << i  << " --> 由工人" << expanded[i] << "完成. "<< " 花费为:" << c[expanded[i]][i] << " " << endl;
	}

	cout << "总花费为:"<< mincost<< endl;
	return 0;
}

好的,我知道这个问题。作业分配问题是指将 $n$ 个作业分配给 $n$ 个人完成,每个人只能完成一个作业,每个作业有一个完成时间和一个收益。要求在完成所有作业的前提下,最大化总收益。分支限界法是一种常用的解决此类问题的算法。 以下是一个示例程序,用于解决作业分配问题: ```python class Job: def __init__(self, time, value): self.time = time self.value = value class Node: def __init__(self, level, time, value, bound): self.level = level self.time = time self.value = value self.bound = bound def bound(node, jobs, n): if node.time >= n: return 0 else: b = node.value t = node.time while t < n and jobs[t].time <= n - t: b += jobs[t].value t += 1 if t < n: b += (n - t) * jobs[t].value / jobs[t].time return b def job_assignment(jobs): n = len(jobs) stack = [] best_node = Node(-1, 0, 0, 0) node = Node(-1, 0, 0, bound(best_node, jobs, n)) while node.level < n - 1: level = node.level + 1 time = node.time + 1 value = node.value + jobs[level].value if time <= n: bound_val = bound(Node(level, time, value, 0), jobs, n) if bound_val > best_node.value: stack.append(Node(level, time, value, bound_val)) if time == n and value > best_node.value: best_node = Node(level, time, value, value) node = stack.pop() if stack else Node(-1, 0, 0, 0) return best_node.value ``` 在这个程序中,`Job` 类用于表示作业,包含属性 `time` 和 `value`,分别表示完成时间和收益。`Node` 类用于表示搜索树中的节点,包含属性 `level`、`time`、`value` 和 `bound`,分别表示当前搜索的层次、已经完成的作业数量、当前已经获得的总收益和当前节点的上界。`bound` 函数用于计算节点的上界。`job_assignment` 函数是程序的入口,用于解决作业分配问题。在函数中,首先创建一个根节点 `node`,然后将其放入栈中。接下来进入循环,每次从栈中取出一个节点进行扩展,直到栈为空或者搜索完所有节点。在节点扩展时,对于每个作业,分别计算将其分配给当前节点代表的人员或者不分配的情况下的上界,并将上界大于当前最优解的节点加入栈中。最终,返回最优解的收益。 希望这个程序能帮助你理解分支限界法的应用。如果有任何问题,欢迎随时问我!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值