某人力资源公司收到了m个合格的求职者的简历,要将他们分发给n个部门,每份简历符合一个或者几个部门的要求,但是每个人的简历最多送给k个部门,每个部门最多可以接受d份简历,如何实现求职者和部门之间的最大配对。使用了最大流算法来解决问题,其中将每份简历最多送给k个部门和每个部门最多接受d份简历的问题通过构建一个流网络来解决。我们使用Ford-Fulkerson算法来实现这个最大流问题的解决。
#include <iostream> // 包含输入输出流库
#include <vector> // 包含vector容器库
#include <cstring> // 包含C风格字符串处理函数
#include <queue> // 包含队列数据结构
#include <algorithm> // 包含常用算法函数,如min
using namespace std; // 使用标准命名空间class MaxFlow { // 定义最大流类struct Edge { // 定义边结构int to, capacity, flow, rev; // 目标节点、容量、流量、反向边索引};int n; // 节点数vector<vector<Edge>> adj; // 邻接表表示图vector<int> level; // 节点层次vector<int> ptr; // 当前弧指针bool bfs(int s, int t) { // 宽度优先搜索构建层次图queue<int> q; // 创建队列level.assign(n, -1); // 初始化所有节点层次为-1level[s] = 0; // 源点层次为0q.push(s); // 源点入队while (!q.empty()) { // 当队列非空时int u = q.front(); // 取出队首元素q.pop(); // 队首元素出队for (const Edge& e : adj[u]) { // 遍历u的所有邻边if (level[e.to] == -1 && e.flow < e.capacity) { // 如果目标节点未访问且边未满level[e.to] = level[u] + 1; // 设置目标节点层次q.push(e.to); // 目标节点入队}}}return level[t] != -1; // 返回是否存在增广路径}int dfs(int u, int t, int pushed) { // 深度优先搜索寻找增广路径if (pushed == 0 || u == t) return pushed; // 如果到达终点或没有可增广的流量,返回for (int& cid = ptr[u]; cid < adj[u].size(); ++cid) { // 遍历u的所有邻边Edge& e = adj[u][cid]; // 获取当前边int v = e.to; // 获取目标节点if (level[u] + 1 == level[v] && e.flow < e.capacity) { // 如果是下一层且边未满int tr = dfs(v, t, min(pushed, e.capacity - e.flow)); // 递归寻找增广路径if (tr == 0) continue; // 如果没有找到增广路径,继续下一条边e.flow += tr; // 正向边增加流量adj[v][e.rev].flow -= tr; // 反向边减少流量return tr; // 返回增广流量}}return 0; // 没有找到增广路径,返回0}public:MaxFlow(int n) : n(n), adj(n), level(n), ptr(n) {} // 构造函数初始化void addEdge(int u, int v, int capacity) { // 添加边Edge a = {v, capacity, 0, adj[v].size()}; // 创建正向边Edge b = {u, 0, 0, adj[u].size()}; // 创建反向边adj[u].push_back(a); // 添加正向边adj[v].push_back(b); // 添加反向边}int getMaxFlow(int s, int t) { // 计算最大流int maxFlow = 0; // 初始化最大流为0while (bfs(s, t)) { // 当存在增广路径时ptr.assign(n, 0); // 重置当前弧指针while (int flow = dfs(s, t, INT_MAX)) { // 寻找增广路径maxFlow += flow; // 累加增广流量}}return maxFlow; // 返回最大流}
};int main() {int m, n, k, d; // 定义变量:求职者数量、部门数量、最多投递数、最多接受数cout << "请输入求职者数量 m: "; // 提示输入求职者数量cin >> m; // 输入求职者数量cout << "请输入部门数量 n: "; // 提示输入部门数量cin >> n; // 输入部门数量cout << "请输入每个求职者最多投递的部门数量 k: "; // 提示输入最多投递数cin >> k; // 输入最多投递数cout << "请输入每个部门最多接受的简历数量 d: "; // 提示输入最多接受数cin >> d; // 输入最多接受数vector<vector<int>> preferences(m); // 创建二维vector存储求职者偏好cout << "请输入每个求职者的部门偏好(每行以空格分隔的部门编号,使用-1结束):\n"; // 提示输入偏好for (int i = 0; i < m; ++i) { // 遍历每个求职者int dept; // 临时存储部门编号while (cin >> dept && dept != -1) { // 输入部门编号直到-1preferences[i].push_back(dept); // 将部门编号添加到偏好列表}}int source = 0; // 源点编号int sink = m + n + 1; // 汇点编号MaxFlow maxFlow(m + n + 2); // 创建最大流对象for (int i = 0; i < m; ++i) { // 遍历每个求职者maxFlow.addEdge(source, i + 1, k); // 添加源点到求职者的边}for (int i = 0; i < n; ++i) { // 遍历每个部门maxFlow.addEdge(m + 1 + i, sink, d); // 添加部门到汇点的边}for (int i = 0; i < m; ++i) { // 遍历每个求职者for (int dept : preferences[i]) { // 遍历求职者的偏好部门maxFlow.addEdge(i + 1, m + 1 + dept, 1); // 添加求职者到部门的边}}int maxMatching = maxFlow.getMaxFlow(source, sink); // 计算最大流cout << "最大配对数量: " << maxMatching << endl; // 输出最大配对数量return 0; // 程序正常结束
}
MaxFlow
类实现了最大流算法,包括构造函数、添加边的方法和计算最大流的方法。bfs
方法用于构建层次图,dfs
方法用于寻找增广路径。main
函数读取输入,包括求职者数量、部门数量、每个求职者最多投递的部门数量和每个部门最多接受的简历数量。- 使用邻接表存储图,并添加相应的边。
- 最后调用
getMaxFlow
方法计算并输出最大配对数量。