分配甲、乙、丙、丁四人去完成五项任务,每人完成各项任务的时间如下表所示。由于任务数多于人数,故规定其中有一个人可完成两项任务,其余三人每人只完成一项任务。试确定总花费时间最少的分配任务方案。(只建立模型,不必求解)
人员\任务 | A | B | C | D | E |
---|---|---|---|---|---|
甲 | 9 | 2 | 4 | 15 | 9 |
乙 | 6 | 5 | 12 | 4 | 2 |
丙 | 11 | 7 | 13 | 4 | 17 |
丁 | 19 | 11 | 15 | 8 | 9 |
建立模型:
解法一:暴力搜索
数据规模较小,可以暴搜求解。
#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