分枝限界法求解任务分配问题

问题描述

有n(n≥1)个任务需要分配给n个人执行,每个任务只能分配给一个人,每个人只能执行一个任务。
第i个人执行第j个任务的成本是c[i][j](1≤i,j≤n)。求出总成本最小的分配方案。
分枝限界法求解任务分配问题_第1张图片

问题求解

这里采用优先队列式分枝限界法求解。
任务和人员的编号均为1~n,解空间每一层对应一个人员的分配。
根结点对应人员0(虚结点),依次为人员1、2、…、n分配任务。
叶子结点对应人员n。
解向量为x:x[i]表示人员i分配任务编号。初始时所有元素值为0,表示没有分配。
临时标识数组worker:worker[i]=true表示任务i已经分配。初始时所有元素值为false,表示没有分配。
用bestx[MAXN]存放最优分配方案, mincost(初始值为∞)存放最优成本。

struct NodeType		//队列结点类型
{
       int no;			//结点编号
   int i;			//人员编号
   int x[MAXN];		//x[i]为人员i分配的任务编号
   bool worker[MAXN];		//worker[i]=true表示任务i已经分配
   int cost;			//已经分配任务所需要的成本
   int lb;			//下界
   bool operator<(const NodeType &s) const	//重载<关系函数
   {
     
	return lb>s.lb;
   }
};

lb为当前结点对应分配方案的成本下界。
例如对于结点e:x[]=[2,1,0,0],表示第1个人员分配任务2,第2个人员分配任务1,第3、4个人员没有分配任务;
相对应有worker[]=[true,true,false,false],表示任务1和2已经分配,而任务3、4还没有分配。此时计算结果是:e.cost=c[1][2]+c[2][1]=2+6=8。
下一步最好的情况是在数组c中第3行和第4行中找到非第1、2列(因为任务1、2已经分配)中最小元素和,显然为1+4=5,即其e.lb=e.cost+5=13。

用bestx[MAXN]存放最优分配方案, mincost(初始值为∞)存放最优成本。
显然一个结点的lb>mincost,则不可能从其子结点中找到最优解,进行剪枝。仅仅扩展lb≤mincost的结点。

代码

//问题表示
int n=4;
int c[MAXN][MAXN]={
     {
     0},{
     0,9,2,7,8},{
     0,6,4,3,7},
	{
     0,5,8,1,8},{
     0,7,6,9,4} };	
				//下标0的元素不用
int bestx[MAXN];		//最优分配方案
int mincost=INF;		//最小成本
int total=1;			//结点个数累计

struct NodeType		//队列结点类型
{
       int no;			//结点编号
   int i;			//人员编号
   int x[MAXN];		//x[i]为人员i分配的任务编号
   bool worker[MAXN];		//worker[i]=true表示任务i已经分配
   int cost;			//已经分配任务所需要的成本
   int lb;			//下界
   bool operator<(const NodeType &s) const	//重载<关系函数
   {
     
	return lb>s.lb;
   }
};

void bound(NodeType &e)
{
     
    int minsum=0;
    for(int i1=e.i+1;i1<=n;i1++)
    {
     
        int minc=INF;
        for(int j1=1;j1<=n;j1++)
            if(e.worker[j1]==false&&c[i1][j1]<minc)//寻找每一列的最小值
                minc=c[i1][j1];
        minsum+=minc;
    }
    e.lb=e.cost+minsum;
}

void bfs()
{
     
    int j;
    NodeType e,e1;
    priority_queue<NodeType> qu;
    memset(e.x,0,sizeof(e.x));
    memset(e.worker,0,sizeof(e.worker));

    e.i=0;
    e.cost=0;
    bound(e);
    e.no=total++;
    qu.push(e);

    while(!qu.empty())
    {
     
        e=qu.top();
        qu.pop();
        if(e.i==n)
        {
     
            if(e.cost<mincost)
            {
     
                mincost=e.cost;
                for(j=1;j<=n;j++)
                    bestx[j]=e.x[j];
            }
        }

        e1.i=e.i+1;
        for(j=1;j<=n;j++)
        {
     
            if(e.worker[j])
                continue;
            for(int i1=1;i1<=n;i1++)
                e1.x[i1]=e.x[i1];
            e1.x[e1.i]=j;
            for(int i2=1;i2<=n;i2++)
                e1.worker[i2]=e.worker[i2];
            e1.worker[j]=true;
            e1.cost=e.cost+c[e1.i][j];
            bound(e1);
            e1.no=total++;
            if(e1.lb<=mincost)
                qu.push(e1);
        }
    }
}

你可能感兴趣的:(算法,队列,算法,bfs,剪枝)