方法一:利用网络流新增源点和汇点的方法
#include <iostream>
#include <vector>
#include <climits>
#include <cstring>
using namespace std;
const int MAX_V = 1100;
struct edge{int to, cap, rev;}; ///邻接表表示,点,容量,反向边
vector<edge> G[MAX_V];
bool used[MAX_V];
/// 贪心策略: 1.找到f < c 或者 f > 0 的边,寻找路径 2.不存在路径则结束,若存在路径则返回1继续寻找
void add_edge(int from, int to, int cap) { ///添加边
G[from].push_back((edge){to, cap, G[to].size()});
G[to].push_back((edge){from, 0, G[from].size() - 1});
}
int dfs(int v, int t, int f) {
if(v == t) return f;
used[v] = true;
for(int i = 0; i < G[v].size(); ++i) {
edge &e = G[v][i];
if(!used[e.to] && e.cap > 0) {
int d = dfs(e.to, t, min(f, e.cap));
if(d > 0) {
e.cap -= d; ///该边减小容量
G[e.to][e.rev].cap += d; ///反向边增加容量
return d;
}
}
}
}
int max_flow(int s, int t) {
int flow = 0;
for(;;) {
memset(used, 0, sizeof(used));
int f = dfs(s, t, INT_MAX);
if(f == 0) return flow;
flow += f;
}
}
/// 0 ~ N - 1 计算机对应的顶点
/// N ~ N + K - 1 任务对应的顶点
int N, K;
int can[MAX_V][MAX_V];
void solve() {
int s = N + K, t = s + 1; ///s 为新的源点,t为新的汇点
for(int i = 0; i < N; ++i) {
add_edge(s, i, 1);
}
for(int i = 0; i < K; ++i) {
add_edge(N + i, t, 1);
}
for(int i = 0; i < N; ++i) {
for(int j = 0; j < K; ++j) {
if(can[i][j]) {
add_edge(i, N + j, 1);
}
}
}
cout << max_flow(s, t) << endl;
}
int main()
{
cin >> N >> K;
int k;
cin >> k;
memset(can, 0, sizeof(can));
for(int i = 0; i < k; ++i) {
int p, q;
cin >> p >> q;
can[p][q] = 1;
can[q][p] = 1;
}
solve();
return 0;
}
/*
3 3
5
0 0
0 1
1 0
1 2
2 1
*/
方法二:贪心法进行增广路
#include <iostream>
#include <vector>
#include <cstring>
const int MAX_V = 1100;
const int INF = INT_MAX;
using namespace std;
int V;
vector<int> G[MAX_V];
int match[MAX_V];
bool used[MAX_V];
///贪心策略:依次遍历每个点,进行增广路径,规则为:未匹配,或已经匹配但未进行遍历的点。
void add_edge(int u, int v)
{
G[u].push_back(v);
G[v].push_back(u);
}
bool dfs(int v)
{
used[v] = true;
for(int i = 0; i < G[v].size(); ++i) {
int u = G[v][i], w = match[u];
if(w < 0 || !used[w] && dfs(w)) { ///该处为该贪心算法关键点
match[v] = u;
match[u] = v;
return true;
}
}
return false;
}
int bipartite_matching()
{
int res = 0;
memset(match, -1, sizeof(match));
for(int v = 0; v < V; v++) {
if(match[v] < 0) {
memset(used, 0, sizeof(used));
if(dfs(v)) {
res++;
}
}
}
return res;
}
int main()
{
int s, x, y;
cin >> s >> V;
for(int i = 0; i < s; ++i) {
cin >> x >> y;
add_edge(x, y);
}
cout << bipartite_matching() << endl;
return 0;
}
/*
5 6
0 3
0 4
1 3
1 5
2 4
*/