分配甲、乙、丙、丁四人去完成五项任务,每人完成各项任务的时间如下表所示

分配甲、乙、丙、丁四人去完成五项任务,每人完成各项任务的时间如下表所示。由于任务数多于人数,故规定其中有一个人可完成两项任务,其余三人每人只完成一项任务。试确定总花费时间最少的分配任务方案。(只建立模型,不必求解)

人员\任务ABCDE
924159
651242
11713417
19111589

建立模型:
解法一:暴力搜索
数据规模较小,可以暴搜求解。

#include <bits/stdc++.h>

using namespace std;
int a[5][6] = {{0, 0,  0,  0,  0,  0},
               {0, 9,  2,  4,  15, 9},
               {0, 6,  5,  12, 4,  2},
               {0, 11, 7,  13, 4,  17},
               {0, 19, 11, 15, 8,  9}};
bool v[10];
map<int, string> mp;
struct sta {
    int sum, two;
    pair<int, int> c;
    vector<pair<int, int> > one;
};
vector<sta> sch;

void dfs(int u, sta now) {
    if (u == 5) {
        if (!sch.empty() && sch.back().sum > now.sum)sch.clear();
        if (sch.empty() || sch.back().sum == now.sum)
            sch.push_back(now);
        return;
    }
    if (!sch.empty() && sch.back().sum < now.sum)return;
    vector<int> c;
    for (int i = 1; i <= 5; i++)if (!v[i])c.push_back(i);
    if (u == 4 && c.size() == 2) {
        v[c[0]] = true, v[c[1]] = true;
        sta nex = now;
        nex.two = u;
        nex.sum += a[u][c[0]] + a[u][c[1]];
        nex.c = make_pair(c[0], c[1]);
        dfs(u + 1, nex);
        v[c[0]] = false, v[c[1]] = false;
        return;
    }
    for (int i = 0; i < c.size(); i++) {
        sta nex = now;
        nex.sum += a[u][c[i]];
        nex.one.emplace_back(u, c[i]);
        v[c[i]] = true;
        dfs(u + 1, nex);
        v[c[i]] = false;
    }
    for (int i = 0; i < c.size(); i++)
        for (int j = i + 1; j < c.size(); j++) {
            v[c[i]] = true, v[c[j]] = true;
            sta nex = now;
            nex.two = u;
            nex.sum += a[u][c[i]] + a[u][c[j]];
            nex.c = make_pair(c[i], c[j]);
            dfs(u + 1, nex);
            v[c[i]] = false, v[c[j]] = false;
        }
}

int main() {
    sta now = {0, 0, {0, 0}, {}};
    dfs(1, now);
    mp[1] = "甲", mp[2] = "乙", mp[3] = "丙", mp[4] = "丁";
    printf("总最小花费时间为:%d\n", sch.back().sum);
    for (int i = 0; i < sch.size(); i++) {
        cout << "方案" << i + 1 << ":" << endl;
        cout << mp[sch[i].two] << "完成任务:" << (char) ('A' + sch[i].c.first - 1) << "和"
             << (char) ('A' + sch[i].c.second - 1) << endl;
        for (int j = 0; j < sch[i].one.size(); j++) {
            cout << mp[sch[i].one[j].first] << "完成任务:" << (char) ('A' + sch[i].one[j].second - 1) << endl;
        }
        puts("");
    }
    return 0;
}
总最小花费时间为:25
方案1:
甲完成任务:B和C
乙完成任务:A
丙完成任务:D
丁完成任务:E

解法二:费用流
建图方式如下图,跑最小费用最大流即可。
在这里插入图片描述

#include<bits/stdc++.h>

using namespace std;
const int N = 20, M = 200;

struct EK {
    int s, t, head[N], ver[M], Next[M], tot = 1, pre[N];
    int mxf, ans, edge[M], c[M], d[N], h[N], n;

    inline void add(int x, int y, int z, int w) {
        n = max({n, x, y});
        ver[++tot] = y, Next[tot] = head[x], edge[tot] = z, c[tot] = w, head[x] = tot;
        ver[++tot] = x, Next[tot] = head[y], edge[tot] = 0, c[tot] = -w, head[y] = tot;
    }

    priority_queue<pair<int, int> > q;

    inline bool dijkstra() {
        memset(d, 0x3f, sizeof(int) * (n + 1));
        while (!q.empty())q.pop();
        q.push({0, s}), d[s] = 0;
        while (!q.empty()) {
            pair<int, int> u = q.top();
            q.pop();
            if (d[u.second] < -u.first)continue;
            for (int i = head[u.second]; i; i = Next[i]) {
                int y = ver[i], z = edge[i], w = c[i];
                if (!z || d[y] <= d[u.second] + w + h[u.second] - h[y]) continue;
                d[y] = d[u.second] + w + h[u.second] - h[y], pre[y] = i;
                q.push({-d[y], y});
            }
        }
        return d[t] != 0x3f3f3f3f;
    }

    inline void upd() {
        for (int i = 0; i <= n; i++)h[i] += d[i];
        int x = t, now = 0x3f3f3f3f;
        while (x != s)now = min(now, edge[pre[x]]), x = ver[pre[x] ^ 1];
        mxf += now, ans += now * h[t];
        x = t;
        while (x != s)
            edge[pre[x]] -= now, edge[pre[x] ^ 1] += now, x = ver[pre[x] ^ 1];
    }

    inline int solve() {
        while (dijkstra())upd();
        return ans;
    }

    inline void init() {
        memset(head, 0, sizeof(int) * (n + 1));
        memset(h, 0, sizeof(int) * (n + 1));
        tot = 1, mxf = ans = n = 0;
    }
} E;

int a[5][6] = {{0, 0,  0,  0,  0,  0},
               {0, 9,  2,  4,  15, 9},
               {0, 6,  5,  12, 4,  2},
               {0, 11, 7,  13, 4,  17},
               {0, 19, 11, 15, 8,  9}};
vector<int> e[5][2];
vector<int> ans[5];
map<int, string> mp;

int main() {
    E.s = 0, E.t = 15;
    E.add(E.s, 5, 1, 0);
    for (int i = 1; i <= 4; ++i) {
        E.add(E.s, i, 1, 0);
        E.add(5, 5 + i, 1, 0);
    }
    for (int i = 1; i <= 4; ++i)
        for (int j = 1; j <= 5; ++j) {
            E.add(i, j + 9, 1, a[i][j]);
            e[i][0].push_back(E.tot);
            E.add(i + 5, j + 9, 1, a[i][j]);
            e[i][1].push_back(E.tot);
        }
    for (int i = 10; i <= 14; ++i)E.add(i, E.t, 1, 0);
    E.solve();
    bool flag = false;
    for (int i = 1; i <= 4; ++i) {
        for (int j:e[i][0])
            if (!E.edge[j ^ 1]) {
                ans[E.ver[j]].push_back(E.ver[j ^ 1] - 9);
                break;
            }
        if (!flag)
            for (int j:e[i][1])
                if (!E.edge[j ^ 1]) {
                    flag = true, ans[E.ver[j] - 5].push_back(E.ver[j ^ 1] - 9);
                    break;
                }
    }
    mp[1] = "甲", mp[2] = "乙", mp[3] = "丙", mp[4] = "丁";
    printf("总最小花费时间为:%d\n", E.ans);
    for (int i = 1; i <= 4; ++i) {
        if (ans[i].size() == 2)
            cout << mp[i] << "完成任务:" << (char) ('A' + ans[i][0] - 1) << "和"
                 << (char) ('A' + ans[i][1] - 1) << endl;
        else
            cout << mp[i] << "完成任务:" << (char) ('A' + ans[i][0] - 1) << endl;
    }
    return 0;
}
总最小花费时间为:25
甲完成任务:C和B
乙完成任务:A
丙完成任务:D
丁完成任务:E
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_sky123_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值