// 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;
}
分配问题-分支限界法
最新推荐文章于 2023-05-05 17:32:32 发布