算法-分支界限法任务分配问题

  描述:任务分配问题要求把n个任务分配给n个人,每个人完成每项任务的成本不同,要求分配总成本最小的分配方案。

 

  int middle_arr[task_size][task_size] = //初始化
    {
        {9,2,7,8},
        {6,4,3,7},
        {5,8,1,8},
        {7,6,9,4}
    };

#include <iostream>//包含 memcpy 二维数组 复制函数 
#include <stdio.h>

#include <queue>  
/*
q.empty()               如果队列为空返回true,否则返回false
q.size()                返回队列中元素的个数
q.pop()                 删除队列首元素但不返回其值
q.front()               返回队首元素的值,但不删除该元素
q.push()                在队尾压入新元素
q.back()                返回队列尾元素的值,但不删除该元素

*/

#define task_size 4//任务 序列 大小 
using namespace std;

int task[task_size][task_size]={
   
   {0}};//先 置为 0,后面 进行 具体 初始化 
int upper = 0;                       // 同 上 
int lower = 0;                       // 同 上 
int row_min[task_size] = {0};        // 同 上 

typedef struct Node
{
	int lb;        //目标函数值 
	int visited[task_size];    //标记已分配任务 
 }Node;

queue<Node> middle; //生成 一个 头结点 序列,为了 使 每个lb 与 每个 任务状态 联系 起来 

void get_upper(int task[][task_size]);//获取最大 界限 
void get_lower(int task[][task_size]);//获取最小 界限 
void init_task();                    //初始 task[num][num],upper,lower 
void bfs(int task[][task_size]);      //bfs 搜索 求解答案 



int minn = 1001;//获取最后 的 结果 

int main()
{
	init_task();//初始 task[num][num],upper,lower 
	
	printf("下界:%d 上界%d\n\n",lower,upper);
	
	bfs(task);  //bfs 搜索 求解答案    
	
	cout << "end result:" << minn;
	return 0;
}

// 横向 搜索 
void bfs(int task[][task_size])//get lb,middle_lb
{
	//生成 一个 初始化 开始 结点(头结点)
	/*********************************************/ 
	
	Node begin;
	begin.lb = lower;
	
	//初始 头结点 
	for(int j = 0;j < task_size;j ++)
	{
		begin.visited[j] = {false};
	}
	
	/********************************************/
	
	middle.push(begin);//头结点 入队(队头) 
	
	int i = 0,flag = 1;
    
    //bfs begin
	while(middle.size() != 0)//队伍 大小 为0 时 推出,不为0 继续 循环 
	{
		
		/***************************************************************************/
		int count = 0;
		for(int m = 0;m < task_size;m ++)//工作 序列 每有 一个 分配,因为是 方阵,故 工作 序列 每有 一个 分配,就 说明 该情况 到了 那层 的dfs,即 该分配哪一个员工了 
		{
			if(middle.front().visited[m] == 1)
			{
				count ++;
			}
			    
		}
		i = count;
		if(i == 4)//是否 所有 任务都能分配完 
		{
			if(middle.front().lb < minn)//当都 分配完后 去 最小的情况 
			{
				minn = middle.front().lb;//当 所有 任务 都分配完时 即 1111 
			}
		}
		/**************************************************************************/ 
		
		int k[task_size] = {false};
		
		Node layer_node = middle.front();//每次 保存 一个出 队后 的结点,便于后面处理 
		middle.pop();                     //形成 每出队 一个 结点 就处理 一个,从队头 出队 
		 
		for(int m = 0;m < task_size;m ++)//保留 上一次 (如果有,没有就为 初始化) 的任务序列,如初始 为0000 然后1000 etc. 
		{
			k[m] = layer_node.visited[m];
		}
		
		for(int j = 0;j < task_size;j ++)
		{
			//如果 满足  lb=已分配任务员工总成本+未分配员工最小成本之和
			if( layer_node.visited[j] == false && ( task[i][j] + (layer_node.lb - row_min[i]) ) <= upper)
			{
				Node p;
				
				for(int m = 0;m < task_size;m ++)//每下一个情况都需要 继承 上一次 情况 的 任务队列 
				{
					p.visited[m] = k[m];
				}
				p.visited[j] = true;             //本次 情况 的更新点 
				
				p.lb = task[i][j] + (layer_node.lb - row_min[i]);//赋值 lb=已分配任务员工总成本+未分配员工最小成本之和 
				
				//打出 每种 情况 下的 上一种 情况,以及本次情况 
				cout << "k :";
				for(int m = 0;m < task_size;m ++)
				{
					cout <<k[m] << " ";
				}
				cout << "p :";
				for(int m = 0;m < task_size;m ++)
				{
					cout <<p.visited[m] << " ";
				}
				cout << "lb: " <<p.lb <<endl;
				
				//每一种 情况 需要 生成 一个 新 结点,然后 入队(队尾) 
				middle.push(p);
				
			}
			
		}
		
		cout << endl;
		
	}
	
	
	
	return;
}

void init_task()//初始化 
{
	int middle_arr[task_size][task_size] = //初始化 
	{
		{9,2,7,8},
		{6,4,3,7},
		{5,8,1,8},
		{7,6,9,4}
	};
	memcpy(task, middle_arr, sizeof(task));//middle_arr ->赋值给 task全局 二维数组 
	get_upper(task);//无返回值 
	get_lower(task);//无返回值 
	
	return;
}

void get_upper(int (*task)[task_size])//get upper
{
	
	int index[task_size] = {false};
	
	for(int i = 0;i < task_size;i ++)//纵向 获取  取每一纵的 最小 值 当 上界 
	{
		int column_min = 1001,flag = 0; 
		
		for(int j = 0;j < task_size;j ++)
		{
			if(index[j] == false && task[j][i] < column_min)
			{
				column_min = task[j][i];
				flag = j;
			}
		}
		
		upper = upper + column_min;//叠加 
		index[flag] = true;
	}
	return;
}

void get_lower(int (*task)[task_size])//get lower
{
	
	for(int i = 0;i < task_size;i ++)//取每一行 的最小值 然后求和 为下限 
	{
		row_min[i] = 1001; 
		
		for(int j = 0;j < task_size;j ++)
		{
			if(task[i][j] < row_min[i])
			{
				row_min[i] = task[i][j];
			}
		}
		
		printf("第%d行最小:%d\n",i + 1,row_min[i]); 
		lower = lower + row_min[i];//叠加 

	}
	
	return;
}

 

end result : 2 + 6 + 1 + 4 = 13

Guess you like

Origin blog.csdn.net/qq_47991812/article/details/120869140