工作分配问题(回溯法)

Description

有n件工作分配给n个人,将工作i分配给第j个人需要支付劳务费用Cij。请为每人分配一个工作,并使得总劳务费用达到最小。



 

输入格式

第一行一个正整数n(1<=n<=11),表示n个工作数,接下来n行,每行代表第i个工作支付给n个不同的人的劳务费用。


 

输出格式

两行。
第一行为最小的总劳务费用。
第二行有n个数,表示工作分配方案。
如下面sample用例的测试数据:
第二行是2 1 3,表示第1个工作分配给第2个人,第2个工作分配给第1个人,第3个工作分配给第3个人。 2+2+5=9
当同时有多种分配方案都能使得总劳务费用相同且都最小,小编号工作优先分配给小编号的人,仅输出这一种方案即可。


 

 

输入样例

3
10 2 3
2 3 4
3 4 5


 

 

输出样例

9
2 1 3


 

 

提示

n个人,任何一种站队排列,都构成搜索的情况。因此,搜索的解空间树是“排列树”。

搜索的算法可以参考书本上“批处理作业调度问题”或“旅行售货员问题”的解法,因为都是排列树的搜索。
套用排列树的回溯算法搜索框架来实现。

 

//
// Created by 15813 on 2019/11/20.
//
#include 
using namespace std;
//人数和工作数
int n;
//最小总工资
int minSalary = 2147483647;
//当前总工资
int curSalary;
//工资矩阵
int **salaryMatrix;
//岗位排列好,挑员工 即x[i]为员工工资
int* x;
int* opt;
void compute();
void trackback(int t);
void swap(int *x, int i, int j);
//控制输出顺序(大岗位给大号人)
int control = 0;

void swap(int *x, int i, int j){
    int temp = x[i];
    x[i] = x[j];
    x[j] = temp;
}

int main(){
    cin >> n;
    salaryMatrix = new int* [n];
    x = new int[n];
    opt = new int[n];
    for(int i = 0; i < n; ++i){
        salaryMatrix[i] = new int[n];
        for(int j = 0; j < n; ++j){
            cin >> salaryMatrix[i][j];
        }
    }
    for(int i = 0;i < n;i++){
        x[i] = i;
    }
    trackback(0);
    cout << minSalary << endl;
    for(int i = 0; i < n; ++i){
        cout << opt[i] + 1 << " " ;
    }
    return 0;
}

void trackback(int t){
//    for(int i = 0; i < n; ++i){
//        cout << opt[i] << " ";
//    }
    //cout << endl;
    if(t >= n){
        compute();
    }
    for(int i = t; i < n; ++i){
        swap(x, i, t);
        trackback(t+1);
        swap(x, i, t);
    }
}

void compute(){
    curSalary = 0;
    int curControl = 0;
    //每一个岗位的工资之和
    for(int i = 0; i < n; ++i){
        curSalary += salaryMatrix[i][x[i]];
    }
    //维护最好的
    if(curSalary < minSalary){
        minSalary = curSalary;
        for(int i = 0; i < n ; ++i){
            opt[i] = x[i];
        }
    }
    if(curSalary == minSalary){
        control = 0;
        for(int i = 0; i < n; ++i) {
            control += (i + 1) * opt[i];
        }
        for(int i = 0; i < n; ++i) {
            curControl += (i + 1) * x[i];
        }
        if(curControl > control){
            control = curControl;
            for(int i = 0; i < n ; ++i){
                opt[i] = x[i];
            }
        }
    }

}

回溯算法,相当于暴力全排列后求最优解,小编号工作优先分配给小编号的人一时没想到什么好方法,就用了比较笨的算i * x[i],大的说明更符合要求。

你可能感兴趣的:(算法笔记)