头像

Cyan

四川成都

深度强化学习炼丹师

信息学竞赛模板(十九)——二分图

信息学竞赛模板(十九)——二分图

2024-10-08 · 27次阅读 · 原创 · 数据结构与算法

相关概念

  • 二分图:如果一张无向图的 N(N>2)N(N>2) 个节点可以分成 A,BA,B 两个非空集合,其中 AB=A\cap B = \emptyset,并且在同一集合内的点之间都没有相连的边,那么称这张图为一张二分图
  • 匹配:任意两端两条边都没有公共端点的边的集合称为图的一组匹配
  • 最大匹配:在二分图中,包含边数最多的一组匹配被称为二分图的最大匹配
  • 增广路:如果在二分图中存在一条连接两个非匹配的点的路径 path,使得非匹配边与匹配边在 path 上交替出现,那么称 path 是匹配 SS增广路

二分图匹配要素

  1. 节点能分成独立的两个集合,每个集合内有 0 条边;
  2. 每个节点只能和一条边进行匹配。

例题

题目

素数伴侣——华为机试题

题解

#include<bits/stdc++.h> using namespace std; const int N = 110, M = 60010; int n, a[N]; bool v[M], vis[N]; //v[i] == false 时为素数 vector<int> g[N]; int match[N]; void init() { v[1] = true; for(int i = 2; i < M; i++) { if(!v[i]) { for(int j = 2 * i; j < M; j += i) v[j] = true; } } } bool dfs(int x) { for(auto &y:g[x]) { if(!vis[y]) { vis[y] = true; if(!match[y] || dfs(match[y])) { match[y] = x; return true; } } } return false; } int main(){ cin >> n; for(int i = 1; i <= n; i++) { scanf("%d", &a[i]); } //筛出最大范围内的素数 init(); //按照奇数和偶数集合分为两个独立的部分: //按照数学定义,两个偶数相加或两个奇数相加必为偶数,而这两个数都大于1, //则必然和大于2,不存在大于2的偶数为素数,所以满足条件的素数伴侣必然 //其中一个为奇数另一个偶数,既可以转化为偶数集合与奇数集合的二分图最大匹配问题 for(int i = 1; i <= n; i++) { if(a[i] & 1) continue; //限制a[i]为偶数 for(int j = 1; j <= n; j++) { if(a[j] & 1 && !v[a[i] + a[j]]) { //限制a[j]为奇数,且a[i]+a[j]为素数 g[i].push_back(j); //加边 } } } //匈牙利算法进行最大匹配,结果在 match 数组中 int ans = 0; for(int i = 1; i <= n; i ++) { if((a[i] & 1) == 0) { memset(vis, false, sizeof vis); if(dfs(i)) ans++; } } cout << ans << endl; return 0; }

标题: 信息学竞赛模板(十九)——二分图
链接: https://www.fightingok.cn/detail/263
更新: 2024-10-08 19:08:23
版权: 本文采用 CC BY-NC-SA 3.0 CN 协议进行许可