分支界限法 任务分配问题

2.5.1题目描述

分配问题要求将n个任务分配给n给人,每个人完成任务的代价不同,要求分配的结果最优,此题可以使用回溯求解。

2.5.2程序使用说明

Java环境1.8.0_111

IDE:eclipse

需要两个文件Node.java,Assignment.java直接编译两个文件,然后直接运行Assignment.java文件,在控制台查看结果。

2.5.3简要分析和设计

假设存在四个人a,b,c,d,任务1,任务2,任务3,任务4,和对应的代价矩阵如下

 


图二 矩阵(来源于算法设计与分析基础第三版)

采用分支界限法,需要计算最优边界Lb,Lb=已分配任务的代价+剩余未分配任务中最小的代价,然后构造状态空间树,上面例子的状态空间树如下:

 

图三  空间树(来源于算法设计与分析基础第三版)

开始节点表示还未给任何人分配任务,然后在开始节点的基础上寻找可扩展节点,由于此时a有四种选择,则有四个扩展节点,然后分别计算可扩展节点的lb,如果lb小于cost,则将其加入优先队列,然后从优先队列中选择一个最优的,作为新的扩展节点,然后在当前节点的基础上为继续进行上述步骤,当有一个节点的状态表示为已将四个节点分配完成,且花费的代价小于已有cost,则更新cost值,然后继续从优先队列里增加值和取值,直到优先队列为空,则最小花费即为最优选择。

2.5.4测试用例

  {{9, 2, 7, 8},

{6, 4, 3, 7},

{5, 8, 1, 8},

{7, 6, 9, 4}}

结果:

人员以此选择工作为:2 1 3 4

最小花费:13

 

2.5.5源代码

目录结构:

 

package three.one;

import java.util.ArrayList;

import java.util.Comparator;

import java.util.PriorityQueue;

/**

 *

 * @author ym

 *

 */

public class Assignment {

//对应花费

private int[][] cost={

        {9, 2, 7, 8},

        {6, 4, 3, 7},

        {5, 8, 1, 8},

        {7, 6, 9, 4}

    };

//构造比较函数

Comparator<Node>  comparator = new Comparator<Node>() {

public int compare(Node o1, Node o2) {

return o1.getLb()-o2.getLb();

};

};

//存储优先队列

PriorityQueue<Node> priorityQueue = new PriorityQueue<Node>(comparator);

//记录当前最优解

int results = 0;

//存储节点

Node resultNode=null;

public Node initRootNode(){

Node root = new Node();

int lb=0;

for(int i=0;i<cost.length;i++){

int min=cost[i][0];

for(int j=1;j<cost[0].length;j++){

if(min>cost[i][j]){

min=cost[i][j];

}

}

lb+=min;

}

root.setLb(lb);//设置lb

return root;

}

/**

 * 计算一个初始值上界

 * @return

 */

public int  mostBound(){

int bound=0;

for(int i=0;i<cost.length;i++){

int max=cost[i][0];

for(int j=1;j<cost[i].length;j++){

if(max<cost[i][j]){

max=cost[i][j];

}

}

bound+=max;

}

return bound;

}

//设置结果

public void setResults(int results) {

this.results = results;

}

 

/**

 * 计算lb

 * @param node

 * @return

 */

public void calculateLb(Node node){

int lb=0;

ArrayList<Integer> upperNode =node.getUpperNode();

int size=upperNode.size();

for(int i=0;i<size;i++){//计算已选person的界

lb+=cost[i][upperNode.get(i)];

}

for(int i=size;i<cost.length;i++){//计算剩余person的最小界

int min=cost[i][0];

for(int j=1;j<cost[i].length;j++){

if(min>cost[i][j]){

min=cost[i][j];

}

}

lb+=min;

}

node.setLb(lb);//更新节点lb

}

/**

 * 计算孩子节点

 * @param node

 * @return

 */

public ArrayList<Node> getChildNodes(Node node){

ArrayList<Node> childNodes = new ArrayList<Node>();//孩子节点

int i=node.getPerson()+1;

int order=0;

ArrayList<Integer> upperNode = node.getUpperNode();//获取已经选择的job

for(int j=0;j<cost[i].length;j++){

if(upperNode==null||order>=upperNode.size()){

Node temp =getNode( i,j,upperNode);//设置节点

childNodes.add(temp);

}

else{

if(order<upperNode.size()&&!upperNode.contains(j)){//构造子节点

Node temp =getNode(i,j,upperNode);//设置节点

childNodes.add(temp);

}

else

order++;

}

}

return childNodes;

}

/**

 *

 *

 * @param i

 * @param j

 * @param list

 * @return

 */

public Node getNode(int i,int j,ArrayList<Integer> list){

ArrayList<Integer> uppers=new ArrayList<Integer>();

if(list!=null&&list.size()>0){

uppers.addAll(list);

}

uppers.add(j);

Node temp = new Node(uppers);

temp.setPerson(i);

temp.setJob(j);

calculateLb(temp);

return temp;

}

 

/**

 *

 * @param node

 */

public void assiginment(Node node){

setResults(mostBound());//计算最大界

priorityQueue.add(node);

while(!priorityQueue.isEmpty()){

Node currentNode = priorityQueue.poll();

if(currentNode.getPerson()<cost.length-1){

ArrayList<Node> childNodes = getChildNodes(currentNode);

for(Node child:childNodes){

if(child.getLb()<results){

priorityQueue.add(child);

}

}

}

else{

if(currentNode.getLb()<results){

results=currentNode.getLb();

resultNode=currentNode;

}

}

}

}

 

public int getResults() {

return results;

}

 

public Node getResultNode() {

return resultNode;

}

public static void main(String[] args){

Assignment at = new Assignment();

Node root=at.initRootNode();

at.assiginment(root);

ArrayList<Integer> list = at.getResultNode().getUpperNode();

System.out.println("人员以此选择工作为:");

for(int i=0;i<list.size();i++){

System.out.print(" "+(list.get(i)+1));

}

System.out.println();

System.out.println("最小花费:");

System.out.print(at.getResults());

}

}

 

package three.one;

 

import java.util.ArrayList;

 

/**

 * Node类

 * @author ym

 *

 */

public class Node{

int person=-1;

int job=-1;

int weight=0;

int lb=0;

ArrayList<Integer> upperNode;

public Node(){

}

public Node(ArrayList<Integer> upperNode){

this.upperNode=upperNode;

}

public int getPerson() {

return person;

}

 

public void setPerson(int person) {

this.person = person;

}

 

public int getJob() {

return job;

}

 

public void setJob(int job) {

this.job = job;

}

 

public int getWeight() {

return weight;

}

 

public void setWeight(int weight) {

this.weight = weight;

}

 

public int getLb() {

return lb;

}

 

public void setLb(int lb) {

this.lb = lb;

}

 

public ArrayList<Integer> getUpperNode() {

return upperNode;

}

 

public void setUpperNode(ArrayList<Integer> upperNode) {

this.upperNode = upperNode;

}

}

  • 13
    点赞
  • 67
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值