CSP-任务分配

引例

任务分配问题要求把n项任务分配给n个人,
每个人完成每项任务的成本不同,要求分配总成本
最小的最优分配方案。如图所示是一个任务分
配的成本矩阵。
在这里插入图片描述
由于本题是一个最优化问题,考虑设计搜索树进行最优搜索求解。
使用算法设计中一个常见的回溯法技巧,分支限界法
既然考虑使用分支限界法,在存放搜索树结点和取用搜索树结点时,考虑设计堆来进行管理

考虑任意一个可行解,例如矩阵中的对角线是一个合法的选择,
表示将任务1分配给人员a、任务2分配给人员b、任务3分配给
人员c、任务4分配给人员d,其成本是9+4+1+4=18;或者应用
贪心法求得一个近似解:将任务2分配给人员a、任务3分配给
人员b、任务1分配给人员c、任务4分配给人员d,其成本是
2+3+5+4=14。显然,14是一个更好的上界。

为了获得下界,考虑人员a执行所有任务的最小代价是2,人员
b执行所有任务的最小代价是3,人员c执行所有任务的最小代
价是1,人员d执行所有任务的最小代价是4。因此,将每一行
的最小元素加起来就得到解的下界,其成本是2+3+1+4=10。
需要强调的是,这个解并不是一个合法的选择(3和1来自于矩
阵的同一列),它仅仅给出了一个参考下界,这样,最优值一
定是[10, 14]之间的某个值。

设当前已对人员1~i分配了任务,并且获得了成本v
,则限界函数可以定义为:
在这里插入图片描述
应用分支限界法求解图1所示任务分配问题,对
解空间树的搜索如下图所示
在这里插入图片描述
针对本题的静态代码设计

//在这里插入代码片
/*
完成任务分配分支限界法的非递归代码
->需要压堆,出堆动作
->需要输出最终结果
*/
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#define N 4
#define INF 0x3f3f3f3f

typedef struct Lnode
{
    int elevate;
    int task;
    struct Lnode* parent;
}TreeNode;

void Init_root(TreeNode*&root,int min)//传入一个TreeNode指针的引用,对这个指针初始化
{
    root=(TreeNode*)malloc(sizeof(TreeNode));
    root->elevate=min;
    root->parent=NULL;
    root->task=-1;
}

void sift_up(TreeNode**&heap,int i)//指针数组的引用
{
    int done=0;
    int w=i;
    if(i==1)
        return;
    while(i>1&&done==0)
    {
        
        {
            if(heap[i]->elevate<heap[i/2]->elevate)
            {
                TreeNode*temp=heap[i];
                heap[i]=heap[i/2];
                heap[i/2]=temp;
            }
            else
            {
                done=1;
            }            
            i=i/2;
        }
    }
}

void sift_down(TreeNode**&heap,int i,int n)
{
    int done=0;
    if(2*i>n)
    {
        return;
    }
    while(2*i<=n&&done==0)
    {
        i=2*i;
        if(i+1<=n&&heap[i+1]->elevate < heap[i]->elevate)
        {
            i=i+1;
        }
        if(heap[i/2]->elevate > heap[i]->elevate)
        {
            TreeNode*temp=heap[i/2];
            heap[i/2]=heap[i];
            heap[i]=temp;
        }
        else
        {
            done=1;
        }
    }
}

int Insert(TreeNode **&heap,int n,TreeNode* x)//heap:(0),1,2,....n
{
    n=n+1;
    heap = (TreeNode**)realloc(heap, (n+1) * sizeof(TreeNode*));
    heap[n]=x;
    sift_up(heap,n);
    return n;
}

int Delete(TreeNode **&heap,int i,int n)//1 =< i <= n
{
    TreeNode*x=heap[i];
    TreeNode*y=heap[n];
    n=n-1;
    //printf("n=%d\n",n);
    if(i==n+1)
        return n;
    heap[i]=y;
    if(y->elevate<=x->elevate)
    {
        sift_up(heap,i);
    }
    else
    {
        sift_down(heap,i,n);
    }
    return n;
}

TreeNode* DeleteMax(TreeNode**&heap,int *n)
{
    TreeNode*x=heap[1];
    *n=Delete(heap,1,*n);
    return x;
}

int main()
{
    int C[N][N]={
        {9,2,7,8},//人员a
        {6,4,3,7},//人员b
        {5,8,1,8},//人员c
        {7,6,9,4},//人员d
    };
    int task[N]={0,0,0,0};
    int max=0;
    int min=0;
    int min_for_each[N]={0,0,0,0};
    for(int i=0;i<N;i++)
    {
        int min_temp=INF;
        int task_temp=-1;
        for(int j=0;j<4;j++)
        {
            if(task[j]==0)
            {
                if(min_temp>C[i][j])
                {
                    min_temp=C[i][j];
                    task_temp=j;
                }
            }            
        }
        max+=min_temp;
        task[task_temp]=1;
    }
    for(int i=0;i<N;i++)
    {
        int min_temp=INF;
        for(int j=0;j<N;j++)
        {
            if(min_temp>C[i][j])
            {
                min_temp=C[i][j];
            }
        }
        min_for_each[i]=min_temp;
        min+=min_temp;
    }
    TreeNode*root;
    Init_root(root,min);
    
    TreeNode **heap= (TreeNode**)malloc(2*sizeof(TreeNode*));
    heap[0]=NULL;
    heap[1]=root;
    int heap_size=1;
    int id=1;//没有找到最优
    while(id==1)
    {
        TreeNode* out_heap=DeleteMax(heap,&heap_size);
        int current_able_task[N]={0,0,0,0};//0 means this task hasn't been arranged
        TreeNode*temp_track=out_heap;
        int w=0;
        while(temp_track->parent!=NULL)
        {
            current_able_task[temp_track->task]=1;
            temp_track=temp_track->parent;
            w++;
        }//检测出堆的结点到根的路径中所有已经被安排的任务,置1

        if(w==4)//到达叶子结点层(实现一种任务分配)
        {
			for(int i=1;i<=heap_size;i++)
			{
				if(heap[i]->elevate<out_heap->elevate)
				{
					id=0;
					break;	
				}	
			} 
			if(id==1)
			{
				TreeNode*temp=out_heap;
				int output[N];
				int j=3;
				while(temp->parent!=NULL)
				{
					output[j]=temp->task;
					j--;
					temp=temp->parent;
				}
				printf("任务分配方案如下:\n");
				for(int j=0;j<N;j++)
				{
					printf("%d ",output[j]+1);
				}
				printf("\n");
				break;
			}
		}
        for(int i=0;i<N;i++)//四种任务
        {
            int elev=out_heap->elevate-min_for_each[w]+C[w][i];//更新安排这个人后的估计值
            if(elev>=min&&elev<=max&&current_able_task[i]==0)//任务合法
            {
                TreeNode*New_node;
                Init_root(New_node,elev);
                New_node->task=i;
                New_node->parent=out_heap;
                heap_size=Insert(heap,heap_size,New_node);//压堆
            }
        }
		
    }
    system("PAUSE");
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值