Task assignment problem | branch and bound method (lower bound)

Task assignment problem

Grades 10 opening time Tuesday, April 14, 2020 10:10
discount 0.8 Discount time Saturday, May 30, 2020 23:55
Late submission allowed no Closing time Saturday, May 30, 2020 23:55

There is only one set of test cases.
Input: The first line is the number of operators n (4=<n<=11), and each of the next n lines has n numbers, which represent the time for the i-th operator to complete the i-th task.
Output: the shortest time to complete all tasks.

  Test input Expected output time limit Memory limit Extra process
Test case 1 Display as text
  1. 4↵
  2. 3 8 4 12↵
  3. 9 12 13 5↵
  4. 8 7 9 3↵
  5. 12 7 6 8↵
Display as text
  1. 21↵
1 second 64M 0

       This problem can of course be solved using backtracking, but branch and bound can also be used here. In any case, all decision trees are traversed, but the branch boundary here is bfs traversal. We discuss each task and assign unselected personnel to it .


1. Construct min_cost array (greedy minimum selection)

        Here is the minimum consumption time, then we must define the lower bound, that is, the minimum consumption that the decision path can achieve. First, we store the minimum time of the i-th thing in min_cost[i] .

/* 找到数组a中的最小元素 */
int findMin(int a[]) {
    int ans = INT_MAX;
    for (int i = 1; i <= n; i++)
        ans = min(ans, a[i]);
    return ans;
}

int min_cost[MAXN];  //min_cost[i]:完成 i 的最小消耗

void setMinCost() {
    for (int i = 1; i <= n; i++) {
        int temp = findMin(Time[i]);
        min_cost[i - 1] = temp;
    }
}

2. Define the lower bound key for the decision point

    For each decision node:

  •  cur_cost records the time consuming of things currently scheduled
  •  The shortest time required for rest_cost to record unscheduled things:\sum_{step} ^{n}rest[ i ]
  •  Lower bound key = cur_cost + rest_cost (the smaller the key, the more likely the decision to find the optimal solution)
  •  The array vis[] records who has been selected
  •  Step means that the 1..step task has been completed, and then consider the task of steak + 1
typedef struct node {
    int key;
    int cur_cost;
    int rest_cost = 0;  //完成step + 1..n的最小消耗
    int step;   //此节点已经完成 1..step 任务

    bool vis[MAXN] = {false};
    /* 构造函数1 */
    node(int cc, int st) {
        cur_cost = cc;
        step = st;
        for (int i = 0; i < n; i++)
            if (!vis[i])
                rest_cost += min_cost[i];
        key = cur_cost + rest_cost;
    };
    /* 构造函数2 */
    node(int cc, int st, bool v[]) {
        cur_cost = cc;
        step = st;
        for (int i = step; i < n; i++)
            if (!vis[i])
                rest_cost += min_cost[i];
        key = cur_cost + rest_cost;
        for (int i = 1; i <= n; i++)
            vis[i] = v[i];
    };

    /* 重载<运算符,以便于优先队列的创建 */
    friend bool operator<(struct node x, struct node y) {
        return x.key > y.key;
    }
} Node;

3. Breadth first search

       Create a priority queue, starting from the root node at first. After that, each time the node with the smallest key is selected for discussion , the next decision is considered in turn, and the decision-making child nodes are added to the priority queue in turn.

      When the node step = n-1 is taken out , it means that the node is considering the last thing, and the minimum value should be updated at this time .

      When the removed node step = n , that is, the node (this is the leaf node) has been allocated, and the minimum value must have been obtained! Exit bfs

void bfs() {
    priority_queue<Node> Q;
    Node head(0, 0);

    while (head.step < n) {
        int step = head.step;
        int cur_cost = head.cur_cost;

        /* 依次选取每一个人 */
        for (int i = 1; i <= n; i++) {
            int maybe = cur_cost + Time[step + 1][i];
            if (head.vis[i] || maybe >= ans)  //约束条件与限界条件
                continue;

            if (step == n - 1)   //正在决策第n件事
                ans = min(ans, maybe);   //更新最小值

            head.vis[i] = true;
            Node temp(maybe, step + 1, head.vis);
            Q.push(temp);
            head.vis[i] = false;
        }

        /* 出队key最小的 */
        head = Q.top();
        Q.pop();
    }
}

4. Complete AC code

         Note: When processing the input, I reversed it. Because I am discussing the allocation of each thing, I hope that the consumption of one thing can be stored in one row~

#include <cstdio>
#include <algorithm>
#include <queue>
#include <climits>

using namespace std;
#define MAXN 13

int Time[MAXN][MAXN];  //time[i][j]:第i件事给第j人做
int n;

/* 找到数组a中的最小元素 */
int findMin(int a[]) {
    int ans = INT_MAX;
    for (int i = 1; i <= n; i++)
        ans = min(ans, a[i]);
    return ans;
}

int min_cost[MAXN];  //min_cost[i]:完成 i 的最小消耗
int ans;

void setMinCost() {
    for (int i = 1; i <= n; i++) {
        int temp = findMin(Time[i]);
        min_cost[i - 1] = temp;
    }
}

void init() {
    scanf("%d", &n);

    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
            scanf("%d", &Time[j][i]);

    setMinCost();
    ans = INT_MAX;
}

typedef struct node {
    int key;
    int cur_cost;
    int rest_cost = 0;  //完成step + 1..n的最小消耗
    int step;   //此节点已经完成 1..step 任务

    bool vis[MAXN] = {false};

    node(int cc, int st) {
        cur_cost = cc;
        step = st;
        for (int i = 0; i < n; i++)
            if (!vis[i])
                rest_cost += min_cost[i];
        key = cur_cost + rest_cost;
    };

    node(int cc, int st, bool v[]) {
        cur_cost = cc;
        step = st;
        for (int i = step; i < n; i++)
            if (!vis[i])
                rest_cost += min_cost[i];
        key = cur_cost + rest_cost;
        for (int i = 1; i <= n; i++)
            vis[i] = v[i];
    };

    friend bool operator<(struct node x, struct node y) {
        return x.key > y.key;
    }
} Node;

void bfs() {
    priority_queue<Node> Q;
    Node head(0, 0);

    while (head.step < n) {
        int step = head.step;
        int cur_cost = head.cur_cost;

        /* 依次选取每一个人 */
        for (int i = 1; i <= n; i++) {
            int maybe = cur_cost + Time[step + 1][i];
            if (head.vis[i] || maybe >= ans)
                continue;

            if (step == n - 1)
                ans = min(ans, maybe);

            head.vis[i] = true;
            Node temp(maybe, step + 1, head.vis);
            Q.push(temp);
            head.vis[i] = false;
        }

        /* 出队key最小的 */
        head = Q.top();
        Q.pop();
    }
}

int main() {
    init();
    bfs();
    printf("%d\n", ans);
}

Guess you like

Origin blog.csdn.net/weixin_43787043/article/details/106235734