如何用二分图算法求解长尾词的最大匹配问题?

2026-04-12 05:401阅读0评论SEO资讯
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计812个文字,预计阅读时间需要4分钟。

如何用二分图算法求解长尾词的最大匹配问题?

题目:给定一个二分图,其中左半部分包含 $n_1$ 个点(编号为 $1$ 到 $n_1$),右半部分包含 $n_2$ 个点(编号为 $1$ 到 $n_2$),二分图共有 $m$ 条边。保证任意一条边的两个端点都不可能在同一部分。

如何用二分图算法求解长尾词的最大匹配问题?

要求:输出结果,包含以下内容:

1.题目

2.二分图的描述,包括:

- 左半部分点数:$n_1$ - 右半部分点数:$n_2$ - 边数:$m$ - 边的描述:每条边由两个端点组成,端点编号分别为 $1$ 到 $n_1$ 和 $1$ 到 $n_2$,且保证端点不在同一部分。

题目

给定一个二分图,其中左半部包含 $n_1$ 个点(编号 $1∼n_1$),右半部包含 $n_2$ 个点(编号 $1∼n_2$),二分图共包含 $m$ 条边。

数据保证任意一条边的两个端点都不可能在同一部分中。

请你求出二分图的最大匹配数。

二分图的匹配:给定一个二分图 $G$,在 $G$ 的一个子图 $M$ 中,$M$ 的边集 ${E}$ 中的任意两条边都不依附于同一个顶点,则称 $M$ 是一个匹配。

二分图的最大匹配:所有匹配中包含边数最多的一组匹配被称为二分图的最大匹配,其边数即为最大匹配数。

输入格式 第一行包含三个整数 $n_1$、 $n_2$ 和 $m$。

接下来 $m$ 行,每行包含两个整数 $u$ 和 $v$,表示左半部点集中的点 $u$ 和右半部点集中的点 $v$ 之间存在一条边。

输出格式 输出一个整数,表示二分图的最大匹配数。

数据范围 $1≤n_1,n_2≤500,1≤u≤n_1,1≤v≤n_2,1≤m≤10^5$ 输入样例:

2 2 4 1 1 1 2 2 1 2 2

输出样例:

2

思路

匈牙利算法:一般用来解决“给定一个二分图,求它的最大匹配”问题。 基本思路:

for i in 1~n1 if find(i): res ++ find(x) { for i in x的所有出边,端点为j if j 未被确认 st[j] = true if j未与左集合匹配,或者j匹配的点z可以匹配一个新点j' match[j] = x }

代码

#include <cstring> #include <iostream> using namespace std; const int N = 510, M = 100010; int n1, n2, m; int h[N], e[M], ne[M], idx; int match[N]; // 存储右集合匹配的左集合的点 int st[N]; // 每一次遍历左集合都要重新初始化 void add(int a, int b) { e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ; } bool find(int x) { for (int i = h[x]; i != -1; i = ne[i]) { int j = e[i]; if (!st[j]) { st[j] = true; if (!match[j] || find(match[j])) { match[j] = x; return true; } } } return false; } int main() { cin >> n1 >> n2 >> m; memset(h, -1, sizeof h); while (m -- ) { int a, b; cin >> a >> b; add(a, b); } int res = 0; for (int i = 1; i <= n1; i ++ ) { memset(st, false, sizeof st); if (find(i)) res ++ ; } cout << res << endl; return 0; }

本文共计812个文字,预计阅读时间需要4分钟。

如何用二分图算法求解长尾词的最大匹配问题?

题目:给定一个二分图,其中左半部分包含 $n_1$ 个点(编号为 $1$ 到 $n_1$),右半部分包含 $n_2$ 个点(编号为 $1$ 到 $n_2$),二分图共有 $m$ 条边。保证任意一条边的两个端点都不可能在同一部分。

如何用二分图算法求解长尾词的最大匹配问题?

要求:输出结果,包含以下内容:

1.题目

2.二分图的描述,包括:

- 左半部分点数:$n_1$ - 右半部分点数:$n_2$ - 边数:$m$ - 边的描述:每条边由两个端点组成,端点编号分别为 $1$ 到 $n_1$ 和 $1$ 到 $n_2$,且保证端点不在同一部分。

题目

给定一个二分图,其中左半部包含 $n_1$ 个点(编号 $1∼n_1$),右半部包含 $n_2$ 个点(编号 $1∼n_2$),二分图共包含 $m$ 条边。

数据保证任意一条边的两个端点都不可能在同一部分中。

请你求出二分图的最大匹配数。

二分图的匹配:给定一个二分图 $G$,在 $G$ 的一个子图 $M$ 中,$M$ 的边集 ${E}$ 中的任意两条边都不依附于同一个顶点,则称 $M$ 是一个匹配。

二分图的最大匹配:所有匹配中包含边数最多的一组匹配被称为二分图的最大匹配,其边数即为最大匹配数。

输入格式 第一行包含三个整数 $n_1$、 $n_2$ 和 $m$。

接下来 $m$ 行,每行包含两个整数 $u$ 和 $v$,表示左半部点集中的点 $u$ 和右半部点集中的点 $v$ 之间存在一条边。

输出格式 输出一个整数,表示二分图的最大匹配数。

数据范围 $1≤n_1,n_2≤500,1≤u≤n_1,1≤v≤n_2,1≤m≤10^5$ 输入样例:

2 2 4 1 1 1 2 2 1 2 2

输出样例:

2

思路

匈牙利算法:一般用来解决“给定一个二分图,求它的最大匹配”问题。 基本思路:

for i in 1~n1 if find(i): res ++ find(x) { for i in x的所有出边,端点为j if j 未被确认 st[j] = true if j未与左集合匹配,或者j匹配的点z可以匹配一个新点j' match[j] = x }

代码

#include <cstring> #include <iostream> using namespace std; const int N = 510, M = 100010; int n1, n2, m; int h[N], e[M], ne[M], idx; int match[N]; // 存储右集合匹配的左集合的点 int st[N]; // 每一次遍历左集合都要重新初始化 void add(int a, int b) { e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ; } bool find(int x) { for (int i = h[x]; i != -1; i = ne[i]) { int j = e[i]; if (!st[j]) { st[j] = true; if (!match[j] || find(match[j])) { match[j] = x; return true; } } } return false; } int main() { cin >> n1 >> n2 >> m; memset(h, -1, sizeof h); while (m -- ) { int a, b; cin >> a >> b; add(a, b); } int res = 0; for (int i = 1; i <= n1; i ++ ) { memset(st, false, sizeof st); if (find(i)) res ++ ; } cout << res << endl; return 0; }