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;
}
}