分支界限法 任務分配問題
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;
}
}