##分支限界法 任务分配问题
#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
using namespace std;
struct Node {
int i, x[10];
bool worker[10];
int cost;
int lb;
bool operator<(const Node &obj) const {
return lb > obj.lb;
}
};
int n;
// 2 6 1 4 13
int *bestx;
int minCost = 9999;
void bound(Node &obj, int **c) {
int minSum = 0;
for (int i1 = obj.i + 1; i1 < n; i1++) {
int minc = 9999;
for (int j1 = 0; j1 < n; j1++)
if (!obj.worker[j1] && c[i1][j1] < minc)
minc = c[i1][j1];
minSum += minc;
}
obj.lb = obj.cost + minSum;
}
void bfs(int **c) {
priority_queue<Node> q;
//初始化节点
Node e;
memset(e.x, -1, sizeof(e.x));
memset(e.worker, false, sizeof(e.worker));
e.i = -1, e.cost = 0;
bound(e, c);
q.push(e);
while (!q.empty()) {
Node e1 = q.top();
q.pop();
if (e1.i == n - 1) {
if (e1.cost < minCost) {
minCost = e.cost;
for (int i = 0; i < n; i++)
bestx[i] = e1.x[i];
}
}
//遍历每个任务
for (int j = 0; j < n; j++) {
Node e2 = e1;
//接e1节点后面没有分配任务的人开始
e2.i++;
if (e2.worker[j])
continue;
//为第i个人分配j任务
e2.x[e2.i] = j;
//任务j分配完成
e2.worker[j] = true;
e2.cost += c[e2.i][j];
bound(e2, c);
if (e2.lb < minCost)
q.push(e2);
}
}
}
int main() {
//录入问题规模,即二维数组的大小,行和列一样
//构造方阵
//可计算10以内,包括10的问题
scanf("%d", &n);
bestx = new int[n];
//初始化矩阵
int **c = new int *[n];
for (int i = 0; i < n; i++)
c[i] = new int[n];
//录入数据
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
scanf("%d", &c[i][j]);
bfs(c);
//打印数据
for (int i = 0; i < n; i++)
printf("%d\t", bestx[i] + 1);
printf("\n");
int sum = 0;
for (int i = 0; i < n; i++)
sum += c[i][bestx[i]];
printf("%d\n", sum);
delete[] bestx;
for (int i = 0; i < n; i++)
delete[] c[i];
delete[] c;
return 0;
}