多智能体(机器人)任务分配问题求解AssignmentProblem
创始人
2024-03-07 18:52:52
0

问题提出:
N个智能体,现在有个任务,就是让N个智能体要到N个目标位置,目标位置不能重复,目标位置与机器人一一对应,要使得期间所有所走的距离之和最短,求解最优任务分配。

在这里插入图片描述

问题抽象:
有N个师父, N个徒弟,每个徒弟只能选者一个师父学习, 每个师父只能带一个徒弟; 每个师父有自己的技能,每个徒弟有自己学习的天分, 当徒弟 j 在师父 i 门下学习, 产生效益为 Aij, 问如何安排使得总效益最大?

求解过程:

定义数据格式:
mi:第i个师父,i=1,2,3,⋯,nm_i: 第 i 个师父, i=1,2,3,⋯,nmi​:第i个师父,i=1,2,3,⋯,n
tj:第j个徒弟,j=1,2,3,⋯n,t_j: 第 j 个徒弟,j=1,2,3,⋯n, tj​:第j个徒弟,j=1,2,3,⋯n,
xij:第j个徒弟是否在第i个师父门下学习:1,是;2不是.x_{ij}: 第j 个徒弟是否在第i 个师父门下学习: 1, 是; 2 不是. xij​:第j个徒弟是否在第i个师父门下学习:1,是;2不是.
aij:第j个徒弟在第i个师父门下学习产生的效益.a_{ij}:第j 个徒弟在第i 个师父门下学习产生的效益.aij​:第j个徒弟在第i个师父门下学习产生的效益.

数学模型:

y=max∑i=1naij.xij(式0)y=max \sum_{i=1}^n a_{ij}.x_{ij} { ( 式0)} y=maxi=1∑n​aij​.xij​(式0)
∑i=1nxij=1,∀j=1,2,3,⋯,n(式1)\sum_{i=1}^n x_{ij} =1 , \forall j=1,2,3,⋯,n { ( 式1)} i=1∑n​xij​=1,∀j=1,2,3,⋯,n(式1)
∑j=1nxij=1,∀i=1,2,3,⋯,n(式2)\sum_{j=1}^n x_{ij} =1 , \forall i=1,2,3,⋯,n { ( 式2)} j=1∑n​xij​=1,∀i=1,2,3,⋯,n(式2)

xij∈{0,1}∀i=1,2,3,⋯,n;j=1,2,3,⋯,n(式3)x_{ij} \in {\lbrace0,1}\rbrace \forall i=1,2,3,⋯,n;j=1,2,3,⋯,n (式3)xij​∈{0,1}∀i=1,2,3,⋯,n;j=1,2,3,⋯,n(式3)

  • 式0 为目标函数, 即最大化总效益;
  • 式1 表示一个师父只能带一个徒弟;
  • 式2 表示一个徒弟只能跟一个师父学习;
  • 式3表示师父-徒弟分配是原子操作,要么分配要么不分配。

在这个抽象的例子中,我们把
师父 ⟺\iff⟺智能体(机器人)
徒弟⟺\iff⟺要去的目标位置位置
效益 ⟺\iff⟺智能体(机器人)当前位置与目标位置二者之间距离

当然这个例子中是求最小,师父徒弟的例子是求最大,道理是一样的。

匈牙利算法

解决分配问题最常用的是匈牙利算法。

按照知乎上某位博主的支付报酬、矩阵求解思路:

若从指派问题的系数矩阵的某行(列)各元素中分别减去或者加上常数k,其最优任务分解问题不变。

这里是引用

通过寻找“0”元素巧妙得出0报酬的指派思路:
给出的代码如下:

#include 
typedef struct matrix
{int cost[101][101];int zeroelem[101][101];int costforout[101][101];int matrixsize;
}MATRIX;
MATRIX hungary;
int result[5041][2];								//用来储存解的结果,第一列表示工人第二列表示工件 
void zeroout(MATRIX &hungary);						//减去行列的最小值得到零元素 
void circlezero(MATRIX &hungary);					//圈出单行列零元素 
void twozero(MATRIX &hungary);						//圈出行列存在两个以上的零元素 
void judge(MATRIX &hungary,int result[2000][2]);	//判断是否符合匈牙利算法条件 
void refresh(MATRIX &hungary);						//不符合条件,对矩阵进行变形 
void output(int result[2000][2],MATRIX hungary);	//结果输出 
MATRIX input();										//初始输入 
int main()
{result[0][0]=0;hungary=input();zeroout(hungary);circlezero(hungary); output(result,hungary);
}
MATRIX input()
{int i,j; matrix hungary;printf("指派问题的匈牙利解法\n");printf("请输入cost矩阵的阶数:\n");scanf("%d",&hungary.matrixsize);printf("请输入代表工人和工件的%d阶矩阵:\n",hungary.matrixsize);for(i=1;i<=hungary.matrixsize;i++)for(j=1;j<=hungary.matrixsize;j++){   scanf("%d",&hungary.cost[i][j]);hungary.costforout[i][j]=hungary.cost[i][j];}return hungary;
}
void zeroout(MATRIX &hungary)
{int i,j; int tem;	//表示同行的最大元素或同列的最大元素 for(i=1;i<=hungary.matrixsize;i++)             //减去同行最大元素{ tem=hungary.cost[i][1];for(j=2;j<=hungary.matrixsize;j++)if(hungary.cost[i][j]tem=hungary.cost[1][j];for(i=2;i<=hungary.matrixsize;i++)if(hungary.cost[i][j]int i,j,p;  int flag; for(i=0;i<=hungary.matrixsize;i++)                         //在矩阵外面构建半圈矩阵标记0的个数;hungary.cost[i][0]=0; for(j=1;j<=hungary.matrixsize;j++)hungary.cost[0][j]=0;for(i=1;i<=hungary.matrixsize;i++)for(j=1;j<=hungary.matrixsize;j++)if(hungary.cost[i][j]==0){hungary.cost[i][0]++;hungary.cost[0][j]++;hungary.cost[0][0]++;} for(i=0;i<=hungary.matrixsize;i++)               //新建一个矩阵for(j=0;j<=hungary.matrixsize;j++)           hungary.zeroelem[i][j]=0;   flag=hungary.cost[0][0]+1;                         //flag = 0的总个数+1while(hungary.cost[0][0]flag=hungary.cost[0][0];                                       //行列单0的情况,for(i=1;i<=hungary.matrixsize;i++)                             //第一遍先行后列{if(hungary.cost[i][0]==1) {for(j=1;j<=hungary.matrixsize;j++)                        if(hungary.cost[i][j]==0&&hungary.zeroelem[i][j]==0)break;hungary.zeroelem[i][j]=1;hungary.cost[i][0]--;hungary.cost[0][j]--;hungary.cost[0][0]--;if(hungary.cost[0][j]>0)for(p=1;p<=hungary.matrixsize;p++)if(hungary.cost[p][j]==0&&hungary.zeroelem[p][j]==0){hungary.zeroelem[p][j]=2;hungary.cost[p][0]--;hungary.cost[0][j]--;hungary.cost[0][0]--;}      }                           }for(j=1;j<=hungary.matrixsize;j++)                            //   第二遍先列后行{if(hungary.cost[0][j]==1){for(i=1;i<=hungary.matrixsize;i++)if(hungary.cost[i][j]==0&&hungary.zeroelem[i][j]==0)break;hungary.zeroelem[i][j]=1;hungary.cost[i][0]--;hungary.cost[0][j]--;hungary.cost[0][0]--;if(hungary.cost[i][0]>0)for(p=1;p<=hungary.matrixsize;p++)if(hungary.cost[i][p]==0&&hungary.zeroelem[i][p]==0){hungary.zeroelem[i][p]=2;hungary.cost[i][0]--;hungary.cost[0][p]--;hungary.cost[0][0]--;}}}}if(hungary.cost[0][0]>0)twozero(hungary);elsejudge(hungary,result);
}
void judge(MATRIX &hungary,int result[5041][2])
{int i,j;int num=0;	//线的条数 int start;	//每组解的储存开始位置 for(i=1;i<=hungary.matrixsize;i++)for(j=1;j<=hungary.matrixsize;j++)if(hungary.zeroelem[i][j]==1)num++;						//划线的条数 if(num==hungary.matrixsize){start=result[0][0]*hungary.matrixsize+1;for(i=1;i<=hungary.matrixsize;i++)for(j=1;j<=hungary.matrixsize;j++)if(hungary.zeroelem[i][j]==1){result[start][0]=i;result[start++][1]=j;}result[0][0]++;}elserefresh(hungary);
}
void twozero(MATRIX &hungary)
{int i,j;int p,q;int m,n;int flag;MATRIX backup;for(i=1;i<=hungary.matrixsize;i++)if(hungary.cost[i][0]>0)break;if(i<=hungary.matrixsize){for(j=1;j<=hungary.matrixsize;j++){backup=hungary;//备份以寻找多解 if(hungary.cost[i][j]==0&&hungary.zeroelem[i][j]==0){hungary.zeroelem[i][j]=1;hungary.cost[i][0]--;hungary.cost[0][j]--;hungary.cost[0][0]--;for(q=1;q<=hungary.matrixsize;q++)if(hungary.cost[i][q]==0&&hungary.zeroelem[i][q]==0){hungary.zeroelem[i][q]=2;hungary.cost[i][0]--;hungary.cost[0][q]--;hungary.cost[0][0]--;}for(p=1;p<=hungary.matrixsize;p++)if(hungary.cost[p][j]==0&&hungary.zeroelem[p][j]==0){hungary.zeroelem[p][j]=2;hungary.cost[p][0]--;hungary.cost[0][j]--;hungary.cost[0][0]--;}flag=hungary.cost[0][0]+1;while(hungary.cost[0][0]flag=hungary.cost[0][0];for(p=i+1;p<=hungary.matrixsize;p++){if(hungary.cost[p][0]==1){for(q=1;q<=hungary.matrixsize;q++)if(hungary.cost[p][q]==0&&hungary.zeroelem[p][q]==0)break;hungary.zeroelem[p][q]=1;hungary.cost[p][0]--;hungary.cost[0][q]--;hungary.cost[0][0]--;for(m=1;m<=hungary.matrixsize;m++)if(hungary.cost[m][q]==0&&hungary.zeroelem[m][q]==0){hungary.zeroelem[m][q]=2;hungary.cost[m][0]--;hungary.cost[0][q]--;hungary.cost[0][0]--;}}}for(q=1;q<=hungary.matrixsize;q++){if(hungary.cost[0][q]==1){for(p=1;p<=hungary.matrixsize;p++)if(hungary.cost[p][q]==0&&hungary.zeroelem[p][q]==0)break;hungary.zeroelem[p][q]=1;hungary.cost[p][q]--;hungary.cost[0][q]--;hungary.cost[0][0]--;for(n=1;n<=hungary.matrixsize;n++)if(hungary.cost[p][n]==0&&hungary.zeroelem[p][n]==0){hungary.zeroelem[p][n]=2;hungary.cost[p][0]--;hungary.cost[0][n]--;hungary.cost[0][0]--;}}}}if(hungary.cost[0][0]>0)                   //确保hungary.cost[][]中的0元素都在zeroelem[][]中被完全标记出来。twozero(hungary);else judge(hungary,result);}           hungary=backup;}}
}
void refresh(MATRIX &hungary)
{int i,j,min=0;int flag1=0,flag2=0;for(i=1;i<=hungary.matrixsize;i++){for(j=1;j<=hungary.matrixsize;j++)if(hungary.zeroelem[i][j]==1){hungary.zeroelem[i][0]=1;         //有独立零元素break;}}while(flag1==0){flag1=1;for(i=1;i<=hungary.matrixsize;i++)if(hungary.zeroelem[i][0]==0){hungary.zeroelem[i][0]=2;for(j=1;j<=hungary.matrixsize;j++)if(hungary.zeroelem[i][j]==2){hungary.zeroelem[0][j]=1;}}for(j=1;j<=hungary.matrixsize;j++){if(hungary.zeroelem[0][j]==1){hungary.zeroelem[0][j]=2;for(i=1;i<=hungary.matrixsize;i++)if(hungary.zeroelem[i][j]==1){hungary.zeroelem[i][0]=0;flag1=0;}}}}                    //对打勾的行和列标记成2 for(i=1;i<=hungary.matrixsize;i++){if(hungary.zeroelem[i][0]==2){for(j=1;j<=hungary.matrixsize;j++){if(hungary.zeroelem[0][j]!=2)if(flag2==0){min=hungary.cost[i][j];flag2=1;}else{if(hungary.cost[i][j]if(hungary.zeroelem[i][0]==2)for(j=1;j<=hungary.matrixsize;j++)hungary.cost[i][j]=hungary.cost[i][j]-min;}for(j=1;j<=hungary.matrixsize;j++){if(hungary.zeroelem[0][j]==2)for(i=1;i<=hungary.matrixsize;i++)hungary.cost[i][j]=hungary.cost[i][j]+min;}                   //未被划线的行减去未被覆盖的最小值,被划线的列加上未被覆盖的最小值 for(i=0;i<=hungary.matrixsize;i++)for(j=0;j<=hungary.matrixsize;j++)hungary.zeroelem[i][j]=0;              //矩阵清0circlezero(hungary); 
}
void output(int result[5041][2],MATRIX hungary)
{int num;	//解的数量 int minsum;	//最小的工作成本 int i,j;char w;int start;  //每个解的储存开始位置 minsum=0;for(i=1;i<=hungary.matrixsize;i++){minsum=minsum+hungary.costforout[i][result[i][1]];}printf("最优解的目标函数值为%d.\n",minsum);num=result[0][0];printf("有%d种解.\n",num);  getchar();for(i=1;i<=num;i++){printf("按任意键输出第%d种解.\n",i);scanf("%c",&w);start=(i-1)*hungary.matrixsize+1;	 for(j=start;j

参考

Assignment Problem(任务分配问题) 详解
Cmd Markdown 公式指导手册
十分钟教你求解分配问题
匈牙利算法详解

相关内容

热门资讯

银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
【NI Multisim 14...   目录 序言 一、工具栏 🍊1.“标准”工具栏 🍊 2.视图工具...
Android|无法访问或保存... 这个问题可能是由于权限设置不正确导致的。您需要在应用程序清单文件中添加以下代码来请求适当的权限:此外...
AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
​ToDesk 远程工具安装及... 目录 前言 ToDesk 优势 ToDesk 下载安装 ToDesk 功能展示 文件传输 设备链接 ...
AsusVivobook无法开... 首先,我们可以尝试重置BIOS(Basic Input/Output System)来解决这个问题。...
ASM贪吃蛇游戏-解决错误的问... 要解决ASM贪吃蛇游戏中的错误问题,你可以按照以下步骤进行:首先,确定错误的具体表现和问题所在。在贪...