二分圖匹配

liuyichen發表於2024-07-04

是麼時二分圖

這個圖的節點可以被分為兩個集合, 使得同一集合內沒有連邊。

匈牙利演算法

例題
IOI 有 $m$ 道題, HPY 會 $n$ 個演算法, 一共有 $k$ 個演算法可以解決IOI題。

HPY 會的演算法太多了, 所有這次 IOI 用了這個演算法, 等到下一次 IOI 時才會記其這個演算法。

<h1 id="constraints">輸入</h1>
第一行輸入三個整數$ n $、$ m $和$ k $:HPY會的演算法的數量、IOI題目的數量和可以解決題目的數量。HPY會的演算法編號為$ 1,2,\dots,n $,IOI題目編號為$ 1,2,\dots,m $。
之後有$ k $行描述用演算法可以解決的問題。每行有兩個整數$ a $和$ b $:演算法$ a $可以解決 IOI 的 $ b $ 號問題。

<h1 id="constraints">輸出</h1>
首先列印一個整數$ r $:最大解決IOI題目數量。之後,列印$ r $行描述解決的題目。你可以列印任何有效的解決方案。
<h1 id="constraints">約束</h1>
<ul>
<li><span class="math inline">$ 1 \le n,m \le 500 $</span></li>
<li><span class="math inline">$ 1 \le k \le 1000 $</span></li>
<li><span class="math inline">$ 1 \le a \le n $</span></li>
<li><span class="math inline">$ 1 \le b \le m $</span></li>
</ul>
<h1 id="example">示例</h1>
<table class="vjudge_sample">
<thead>
  <tr>
    <th>Input</th>
    <th>Output</th>
  </tr>
</thead>
<tbody>
  <tr>
    <td><pre>3 2 4
1 1
1 2
2 1
3 1
</pre></td>
    <td><pre>2
1 2
3 1
</pre></td>
  </tr>
</tbody>
</table>
</div>

對於一個點, 如果它沒有匹配, 找它能匹配的點, 如果可以沒有匹配或者可以換一個匹配就可以

#include<bits/stdc++.h>

using namespace std;

const int N = 505;

vector<int>g[N];
int vis[N], n, m, q, u, v, ans, p[N];

bool dfs(int x){
  if(vis[x]){
    return 0;
  }
  vis[x] = 1;
  for(auto v : g[x]){
    if((!p[v] || dfs(p[v]))){
      p[v] = x;
      return 1;
    }
  }
  return 0;
}

int main(){
  cin >> n >> m >> q;
  while(q--){
    cin >> u >> v;
    g[u].push_back(v);
  }
  for(int i = 1; i <= n; ++i){
    for(int j = 1; j <= n; ++j){
      vis[j] = 0;
    }
    ans += dfs(i);
  }
  cout << ans << '\n';
  for(int i = 1; i <= m; ++i){
    if(p[i]){
      cout << p[i] << ' ' << i << '\n';
    }
  }
  return 0;
}

時間複雜度 \(O(n \cdot (n + m))\)

空間複雜度 \(O(n + m)\)

相關文章