最初想自己写,没成功
参考了一下这个

  • http://www.cnblogs.com/chenyg32/p/3293247.html

用的方法是《运筹学(第4版)》,《运筹学》教材编写组编,清华大学出版社
6.5指派问题的匈牙利算法
上面是用c++写的,我改成了java,但不是完全一样,应该是比原作者时间复杂度低。

用-1标记φ,-2标记◎(独立零元素)。
在第二步(4)中需要随机选,第三步发现选错了需要返回的,所以可以用一个栈存储 二(4)之后的东西,发现选错了恢复为0。

有一个问题没有处理好,就是二(4)选了以后,到第三步错了,课本上说的是回到二(4)另行试探,就是不能重复原来的那种选法了。而我每次都是随机选,随机的话有一定概率一直选到那个错的元素,这样就结束不了。

还有一点,在第二步里面删除同行同列可以遍历,但是当元素个数多的时候遍历太慢,可以用一下十字链表,有心的人可以实现一下

下面的Main_Node就是记录下某行某列的节点


package fd;public class Main_Node {int row;
int col;
public Main_Node(int row, int col) {super();this.row = row;this.col = col;
}
}

看程序可以从main开始看,缕清结构

//记录每行每列0的个数public static void countZero(int []row,int[]col){for (int i = 0; i < n; ++i){for (int j = 0; j < n; ++j)if (p[i][j] == 0){row[i]++; col[j]++;}}}
//画最少的线覆盖所有0元素 public static int  drawLine(){    for(int i=0;i<n;i++)for(int j=0;j<n;j++)q[i][j]=0;for (int i = 0; i < n; ++i)x[i] = 1;for (int j = 0; j < n; ++j)y[j] = 0;//row 对所有不含独立0元素的行打勾! for (int i = 0; i < n; ++i){for (int j = 0; j < n; ++j){if (p[i][j] == -2){x[i] = 0;break;}}}boolean is = true;while (is)    //循环直到没有勾可以打 {is = false;//col 对打勾的行中含φ元素的未打勾的列打勾 for (int i = 0; i < n; ++i){if (x[i] == 1){for (int j = 0; j < n; ++j){if (p[i][j] == -1 && y[j] == 0){y[j] = 1;is = true;}}}}//row 对打勾的列中含◎的未打勾的行打勾 for (int j = 0; j < n; ++j){if (y[j] == 1){for (int i = 0; i < n; ++i){if (p[i][j] ==-2&& x[i] == 0){x[i] = 1;is = true;}}}}}//没有打勾的行和有打勾的列画线,这就是覆盖所有0元素的最少直线数 int line = 0;for (int i = 0; i < n; ++i){if (x[i] == 0){for (int j = 0; j < n; ++j)q[i][j]++;line++;}if (y[i] == 1){for (int j = 0; j < n; ++j)q[j][i]++;line++;}}return line;}
//更新行列的0且进栈public static void refresh1(int index,int index2,int[]row,int[]col){for (int j = 0; j < n; ++j)if (p[index][j] == 0)//若该行还有0且没被划掉才更新 {row[index]--;col[j]--;p[index][j]=-1;stack[++top]=new Main_Node(index,j);}for (int i = 0; i < n; ++i)if (p[i][index2] == 0){row[i]--;col[index2]--;p[i][index2]=-1;stack[++top]=new Main_Node(i,index2);}}//更新行列的0不进栈public static void refresh2(int index,int index2,int[]row,int[]col){for (int j = 0; j < n; ++j)if (p[index][j] == 0)//若该行还有0且没被划掉才更新 {row[index]--;col[j]--;p[index][j]=-1;}for (int i = 0; i < n; ++i)if (p[i][index2] == 0){row[i]--;col[index2]--;p[i][index2]=-1;}}
//第二步、//找独立0元素个数 /*1.找含0最少的那一行/列    2.划掉,更新该行/列0元素所在位置的row[],col[]3.直到所有0被划线退出      4.need为false说明只做了前两步,need为true说明做了第四步(第四步是猜的,所以要进栈,如果第三步发现猜错了,出栈)*/public static int find(){int zero=0;     //独立0元素的个数int []row=new int[n]; int []col=new int[n];//行列0元素个数 countZero(row,col);while (true){  for(int i=0;i<n;i++){if (row[i] == 0)row[i] = Integer.MAX_VALUE;if (col[i] == 0)col[i] = Integer.MAX_VALUE;}boolean stop = true;int row_min=Arrays.stream(row).min().getAsInt();int col_min= Arrays.stream(col).min().getAsInt();if(row_min==Integer.MAX_VALUE)  break;if (row_min<=col_min)    //行有最少0元素 {    if(row_min>1){need_stack=true;}//找含0最少的那一行 int tmp = Integer.MAX_VALUE; int index = -1;for (int i = 0; i < n; ++i){if (tmp > row[i]){tmp = row[i];index = i;}}/*找该行任意一个没被划掉的0元素(独立0元素),任意找一个*/ int index2 = -1;            //该行独立0元素的列值int count=(int)(Math.random()*row[index]);//随机选哪一个0int k=0; for (int i = 0; i < n; ++i)if (p[index][i] == 0){ if(k==count){index2 = i;stop = false;            //找到独立0元素则继续循环 zero++;                //独立0元素的个数 break;}k++;}//找不到独立0元素了 if (stop)    break;//标记 row[index]--;col[index2]--;    p[index][index2] =-2;//独立0元素if(need_stack){stack[++top]=new Main_Node(index,index2);refresh1(index,index2,row,col);//更新其他0且都要进栈}else refresh2(index,index2,row,col);}else       //列有最少0元素 {    if(col_min>1){need_stack=true;}int tmp = Integer.MAX_VALUE;int index = -1;for (int i = 0; i < n; ++i){if (tmp > col[i]){tmp = col[i];index = i;}}int index2 = -1;int count=(int)(Math.random()*col[index]);//随机选哪一个0int k=0; for (int i = 0; i < n; ++i)if (p[i][index] == 0){  if(k==count){index2 = i;stop = false;            //找到独立0元素则继续循环 zero++;                //独立0元素的个数 break;}k++;}if (stop)break;row[index2]--;col[index]--;p[index2][index] =-2;if(need_stack){stack[++top]=new Main_Node(index2,index);refresh1(index2,index,row,col);//更新其他0且都要进栈}else refresh2(index2,index,row,col);}}return zero;}
package fd;import java.util.Arrays;
import java.util.Scanner;public class Main {//define Max 100public static int max=100;public static int n;                    //维数 public static int [][]s=new int[max][max];        //原始矩阵 public static int [][]p=new int[max][max];        //归约矩阵 public static int [][]q=new int[max][max];        //0:未被画线 1:画了1次 2: 画了2次(交点) public static int []x=new int[max];public static int []y=new int[max];       //画线时是否被打勾,1是0不是 public static boolean need_stack=false;//当为true时,需要进栈public static Main_Node stack[]=new Main_Node[10000];public static int top=-1;//在规约矩阵里面0是0   //-1φ,-2是◎(独立零元素)//三做完后如果返回可能要回退栈内的元素public static void main(String[] args) {//第零步:输入矩阵System.out.println("请输入一个<=100的阶数:");Scanner in =new Scanner(System.in);n=in.nextInt();System.out.println("矩阵元素:");for(int i=0;i<n;i++)for(int j=0;j<n;j++){s[i][j]=in.nextInt();p[i][j]=s[i][j];}in.close();//第一步:变出零来for(int i=0;i<n;i++){int min=p[i][0];for(int j=1;j<n;j++)min=Math.min(min, p[i][j]);if(min!=0){for(int j=0;j<n;j++)p[i][j]-=min;}}for(int j=0;j<n;j++){int min=p[0][j];for(int i=1;i<n;i++)min=Math.min(min, p[i][j]);if(min!=0){for(int i=0;i<n;i++)p[i][j]-=min;}}//第二步find()int t=n;//t是本次find()要找的个数//在第二步里是n,第三步回退的是top+1//第四步还是nwhile(find()<t){ t=top+1;//进栈的元素个数,也是出栈的元素个数//第三步drawLineif(drawLine()==n)//将元素退栈,返回第二步{while(top!=-1){Main_Node aaa=stack[top--];p[aaa.row][aaa.col]=0;}continue; }//第四步//最小的未被划线的数int min = Integer.MAX_VALUE;for (int i = 0; i < n; ++i)for (int j = 0; j < n; ++j)    if (q[i][j] == 0 && min > p[i][j])min = p[i][j];//更新未被划到的和交点 for (int i = 0; i < n; ++i)for (int j = 0; j < n; ++j)if (q[i][j] == 0)p[i][j] -= min;else if (q[i][j] == 2)p[i][j] += min;//恢复-1、-2为0   ,   t=nfor(int i=0;i<n;i++)for(int j=0;j<n;j++)if(p[i][j]<0)   p[i][j]=0;t=n;}//求和及输出 int ans = 0;for (int i = 0; i < n; ++i)for (int j = 0; j < n; ++j)if (p[i][j] == -2){System.out.println("行为"+i+",列为"+j);ans += s[i][j];}System.out.println(ans);                                 }}  

匈牙利算法解决指派问题(java版)相关推荐

  1. 匈牙利算法解决指派问题清晰流程

    匈牙利算法解决指派问题清晰流程 百度词条上,指派问题(Assignment problem)是这么定义的:在满足特定指派要求条件下,使指派方案总体效果最佳.如:有若干项工作需要分配给若干人(或部门)来 ...

  2. Hungarian method 匈牙利算法 解决指派问题

    这个也讲得不错: https://blog.csdn.net/Wonz5130/article/details/80678410 from scipy.optimize import linear_s ...

  3. 学习匈牙利算法解决指派问题

    指派问题 指派问题的标准形式 指派问题的数学模型 非标准形式的指派问题 指派问题的匈牙利解法的一般步骤 以上步骤并不好理解下面进行一些实例展示方便理解 匈牙利解法的实例 这是一个比较友好的例子,一切按 ...

  4. 数据结构与算法基础(java版)

    目录 数据结构与算法基础(java版) 1.1数据结构概述 1.2算法概述 2.1数组的基本使用 2.2 数组元素的添加 2.3数组元素的删除 2.4面向对象的数组 2.5查找算法之线性查找 2.6查 ...

  5. 匈牙利算法求解指派问题(C++代码)

    前言 匈牙利算法能精确求解指派问题,获取最优分配方案.匈牙利算法求解指派问题基于以下原理:在一个成本矩阵中,对某一行或者某一列加上或减去一个数,最优的分配方案不变.基于此原理,我们可以对成本矩阵进行变 ...

  6. 匈牙利算法解决二分图匹配问题

    匈牙利算法是由匈牙利数学家Edmonds于1965年提出.匈牙利算法是基于Hall定理中充分性证明的思想,它是二分图匹配最常见的算法,该算法的核心就是寻找增广路径,它是一种用增广路径求二分图最大匹配的 ...

  7. java动态分区分配_操作系统 动态分区分配算法课程设计 java版.pdf

    操作系统 动态分区分配算法课程设计 java版 湖 南 文 理 学 院 实 验 报 告 课程名称 操作系统课程设计 实验名称 存储管理--动态分区分配算法的模拟 成绩 学生姓名 曹乐 专业 计算机 班 ...

  8. 匈牙利算法解指派问题(Java代码)

    先介绍匈牙利算法 (Hungary) 的求解过程,我直接把代码贴上去就可以吧,有需要的可以联系我. 这个java代码是我根据 "数据魔术师" 公众号中的 c++ 代码改过来的,算是 ...

  9. 雪花算法id长度_【Java】分布式自增ID算法雪花算法 (snowflake,Java版)

    作者:H__D 转载自: https://www.cnblogs.com/h--d/p/11342741.html 一般情况,实现全局唯一ID,有三种方案,分别是通过中间件方式.UUID.雪花算法. ...

  10. 算法之BTree(Java版)

    BTree 介绍 BTree算法笔者就不介绍了,应用范围十分广泛,但是网络上很多关于Java版本的实现多多少少都有问题.笔者是根据Google GO语言的标椎实现库,实现的Java版.对于相同的输入, ...

最新文章

  1. 顺序表-删除所有元素值为x结点(另建表存放+复制到原表)
  2. Sqlite表的结构修改
  3. java list移除所有元素,从List中移除指定 List 中包含的其所有元素(可选操作)。...
  4. 小程序云开发搜索功能的实现正则_几行代码实现小程序云开发提现功能
  5. Linux下实现USB口的热插拔
  6. OpenCV限制对比度自适应直方图均衡(CLAHE)的实例(附完整代码)
  7. php判断ie版本,PHP获取浏览器版本信息
  8. SQL中PIVOT 行列转换
  9. 【无码专区4】幸运数字4(折半搜索+计数+结论)
  10. Redis+MongoDB 极佳实践:做到读写分离
  11. ThinkPHP框架 _ 学习11
  12. 高中信息技术——Flash动画制作刷题点整理(二)
  13. 超级好看的windows终端美化教程
  14. 十年游戏建模师给想学次世代游戏建模同学的一些忠告,太受益了
  15. 手机计算机应用的图片,怎么把手机的照片传到电脑 四种方法轻松导入
  16. Matlab中如何清除persistent 变量
  17. 30本从禁书到名著的阅读书单
  18. Processing入门简介
  19. visual studio C++冒号:与双冒号::的使用说明
  20. “通过端口 1433 连接到主机 127.0.0.1 的 TCP/IP 连接失败。错误:“connect timed out。请验证连接属性,并检查 SQL Server……”解决问题

热门文章

  1. shell脚本小程序之特洛伊木马示例
  2. Solr全文检索学习笔记·记录
  3. 【密码学】抽象代数——群(学习笔记)
  4. 5.1 Lilypond五线谱
  5. 超级电容的电压均衡板
  6. ios9提取安装包ipa_iOS获取App ipa包
  7. 微机原理与接口技术-第二版-课后习题答案 绪论
  8. 在银行做数据是一种什么体验?
  9. LeetCode题解:幂集
  10. c语言编程汉诺塔问题,C语言解决汉诺塔问题