uestc SOUND OF DESTINY

邻接表版的DFS形式的二分匹配

增广路求最大匹配数

匈牙利算法的要点如下

  1. 从左边第 1 个顶点开始,挑选未匹配点进行搜索,寻找增广路。

    1. 如果经过一个未匹配点,说明寻找成功。更新路径信息,匹配边数 +1,停止搜索。
    2. 如果一直没有找到增广路,则不再从这个点开始搜索。事实上,此时搜索后会形成一棵匈牙利树。我们可以永久性地把它从图中删去,而不影响结果。
  2. 由于找到增广路之后需要沿着路径更新匹配,所以我们需要一个结构来记录路径上的点。DFS 版本通过函数调用隐式地使用一个栈,而 BFS 版本使用 prev 数组。

  详细介绍http://www.renfei.org/blog/bipartite-matching.html

bool 寻找从k出发的对应项出的可增广路
{
    while (从邻接表中列举k能关联到顶点j)
    {
        if (j不在增广路上)
        {
            把j加入增广路;
            if (j是未盖点 或者 从j的对应项出发有可增广路)
            {
                修改j的对应项为k;
                则从k的对应项出有可增广路,返回true;
            }
        }
    }
    则从k的对应项出没有可增广路,返回false;
}

void 匈牙利hungary()
{
    for i->1 to n
    {
        if (则从i的对应项出有可增广路)
            匹配数++;
    }
    输出 匹配数;
}

  

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstdlib>
 4 #include<cstring>
 5 #include<string>
 6 #include<queue>
 7 #include<algorithm>
 8 #include<map>
 9 #include<iomanip>
10 #include<climits>
11 #include<string.h>
12 #include<cmath>
13 #include<stdlib.h>
14 #include<vector>
15 #define INF 1e7
16 #define MAXN 100010
17 #define maxn 1000010
18 #define Mod 1000007
19 #define N 1010
20 using namespace std;
21 typedef long long LL;
22
23 int n, m, k, a, b, ans;
24 bool vis[N];
25 int match[N];
26 vector<int> G[N];
27
28 bool Search_path(int src)
29 {
30     for (int i = 0; i < G[src].size(); ++i) {
31         int v = G[src][i];
32         if (!vis[v]) {              
33             vis[v] = true;            
34             if (match[v] == -1 || Search_path(match[v])) {
35                 match[v] = src;
36                 return true;
37             }
38         }
39     }
40     return false;                   
41 }
42
43 void init()
44 {
45     ans = 0;
46     for (int i = 0; i <= n; ++i)
47         G[i].clear();
48     memset(match,-1,sizeof(match));
49 }
50
51 int main()
52 {
53     while (cin >> n >> m) {
54         init();
55         cin >> k;
56         for (int i = 0; i < k; ++i) {
57             cin >> a >> b;
58             a--, b--;
59             G[a].push_back(b);
60         }
61         for (int i = 0; i < n; ++i) {
62             memset(vis,0,sizeof(vis));
63             if (Search_path(i))
64                 ans++;
65         }
66         cout << ans << endl;
67     }
68     return 0;
69 }

附上模板

 1 // 顶点、边的编号均从 0 开始
 2 // 邻接表储存
 3
 4 struct Edge
 5 {
 6     int from;
 7     int to;
 8     int weight;
 9
10     Edge(int f, int t, int w):from(f), to(t), weight(w) {}
11 };
12
13 vector<int> G[__maxNodes]; /* G[i] 存储顶点 i 出发的边的编号 */
14 vector<Edge> edges;
15 typedef vector<int>::iterator iterator_t;
16 int num_nodes;
17 int num_left;
18 int num_right;
19 int num_edges;

DS

 1 queue<int> Q;
 2 int prev[__maxNodes];
 3 int Hungarian()
 4 {
 5     int ans = 0;
 6     memset(matching, -1, sizeof(matching));
 7     memset(check, -1, sizeof(check));
 8     for (int i=0; i<num_left; ++i) {
 9         if (matching[i] == -1) {
10             while (!Q.empty()) Q.pop();
11             Q.push(i);
12             prev[i] = -1; // 设 i 为路径起点
13             bool flag = false; // 尚未找到增广路
14             while (!Q.empty() && !flag) {
15                 int u = Q.front();
16                 for (iterator_t ix = G[u].begin(); ix != G[u].end() && !flag; ++ix) {
17                     int v = edges[*ix].to;
18                     if (check[v] != i) {
19                         check[v] = i;
20                         Q.push(matching[v]);
21                         if (matching[v] >= 0) { // 此点为匹配点
22                             prev[matching[v]] = u;
23                         } else { // 找到未匹配点,交替路变为增广路
24                             flag = true;
25                             int d=u, e=v;
26                             while (d != -1) {
27                                 int t = matching[d];
28                                 matching[d] = e;
29                                 matching[e] = d;
30                                 d = prev[d];
31                                 e = t;
32                             }
33                         }
34                     }
35                 }
36                 Q.pop();
37             }
38             if (matching[i] != -1) ++ans;
39         }
40     }
41     return ans;
42 }

BFS

 1 int matching[__maxNodes]; /* 存储求解结果 */
 2 int check[__maxNodes];
 3
 4 bool dfs(int u)
 5 {
 6     for (iterator_t i = G[u].begin(); i != G[u].end(); ++i) { // 对 u 的每个邻接点
 7         int v = edges[*i].to;
 8         if (!check[v]) {     // 要求不在交替路中
 9             check[v] = true; // 放入交替路
10             if (matching[v] == -1 || dfs(matching[v])) {
11                 // 如果是未盖点,说明交替路为增广路,则交换路径,并返回成功
12                 matching[v] = u;
13                 matching[u] = v;
14                 return true;
15             }
16         }
17     }
18     return false; // 不存在增广路,返回失败
19 }
20
21 int hungarian()
22 {
23     int ans = 0;
24     memset(matching, -1, sizeof(matching));
25     for (int u=0; u < num_left; ++u) {
26         if (matching[u] == -1) {
27             memset(check, 0, sizeof(check));
28             if (dfs(u))
29                 ++ans;
30         }
31     }
32     return ans;
33 }

DFS

时间: 2024-10-04 07:17:15

uestc SOUND OF DESTINY的相关文章

UESTC 919 SOUND OF DESTINY --二分图最大匹配+匈牙利算法

二分图最大匹配的匈牙利算法模板题. 由题目易知,需求二分图的最大匹配数,采取匈牙利算法,并采用邻接表来存储边,用邻接矩阵会超时,因为邻接表复杂度O(nm),而邻接矩阵最坏情况下复杂度可达O(n^3). 代码: #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <vector> u

UESTC 电子科大专题训练 数据结构 D

UESTC 1584 题意:平面坐标上有n个怪物,每个怪物有一个rank值,代表x坐标和y坐标都不大于它本身的怪物数(不包括本身) 思路:对x y坐标从小到大排序,x优先排序,用数状数组计算y坐标小于它的数量 AC代码: #include "iostream" #include "string.h" #include "stack" #include "queue" #include "string" #i

UESTC 31 饭卡(Card) --背包问题

背包问题. 思路:如果m<5,此时也不能消费,所以此时答案为m m>=5: 求出背包容量为m-5,买前n-1样便宜的菜(排个序)的最大价值(即最大消费,即消费完后剩余值最接近5)最后减去最大的那个菜的价格,就得到最小的余额. 代码: #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using n

UESTC 电子科大专题训练 数据结构 A

UESTC 1591 题意:求区间极值之差 思路:线段树裸题,不带更新 ACA代码: #include "iostream" #include "string.h" #include "stack" #include "queue" #include "string" #include "vector" #include "set" #include "ma

2017 UESTC Training for Data Structures

2017 UESTC Training for Data Structures A    水,找区间极差,RMQ怼上去. #include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define rep(i,a,b) for (int i=a;i<=b;i++) #define per(i,b,a) for (int i=b;i&

UESTC - 878 温泉旅店 二维费用背包问题

http://acm.uestc.edu.cn/#/problem/show/878 设dp[i][j][k]表示在前i个数中,第一个得到的异或值是j,第二个人得到的异或值是k的方案数有多少种. 因为异或后的大小不确定,所以不能压缩数组,但是也不大..可以过. #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <algorithm>

ACM:UESTC - 649 括号配对问题 - stack

  UESTC - 649  括号配对问题 Time Limit: 1000MS   Memory Limit: 65535KB   64bit IO Format: %lld & %llu Description 大家都知道算术表达式中,括号必须配对,现在任意给出一个算术表达式,判断其括号是否配对.如果配对,输出Yes,否则输出No. Input 含多组测试数据,输入首先是一个整数T表示测试数据组数(0<T≤300).随后有T行测试数据,长度不超过1000个字符,字符串间不含空格. Out

2015 CCPC D- Pick The Sticks(UESTC 1218) (01背包变形)

http://acm.uestc.edu.cn/#/problem/show/1218 既然二维dp表示不了,就加一维表示是否在边界放置,放置一个,两个.有一个trick就是如果只放一根,那么多长都可以. wa了好多次(囧) 开始因为l[i]/2会出现小数,没注意,把所有的长度都x2就可以解决. 又wa了n次因为没注意j-l[i]时没加判断,为什么不是RE呢!不开心... /********************************************* Memory: 1140 KB

1342: [Baltic2007]Sound静音问题

1342: [Baltic2007]Sound静音问题 Time Limit: 5 Sec  Memory Limit: 162 MBSubmit: 710  Solved: 307[Submit][Status][Discuss] Description 静音问题 数字录音中,声音是用表示空气压力的数字序列描述的,序列中的每个值称为一个采样,每个采样之间间隔一定的时间. 很多声音处理任务都需要将录到的声音分成由静音隔开的几段非静音段.为了避免分成过多或者过少的非静音段,静音通常是这样定义的:m