《啊哈!演算法》我要做月老 ——二分圖最大匹配

Iovebecky發表於2018-08-24

#####題目描述
小哼今天和小夥伴們一起去遊樂場玩,終於可以坐上夢寐以求的過山車了。過山車的每一排只有兩個座位,為了安全起見,是每個女生必須和一個男生做一排。但是,每個人都希望與自己認識的人坐在一起。如何安排才可以讓更多認識的男生和女生坐在一起呢?

輸入

輸入第一行為兩個整數n,m。n表示有n個人(其中前1~n/2號為女生,n/2+1~n號為男生),m表示有m個關係。(1 < n,m < 10)

後面m行,每行兩個數a,b,表示a和b互相認識。

輸出

輸出最大匹配個數(最多有幾對男生女生可以坐在一起)

樣例輸入

6 5
1 4
1 5
2 5
2 6
3 4

樣例輸出

3

vector臨接表

#include <iostream>
#include <cstring>
#include <vector>
using namespace std;

const int maxn = 505;
int n, m;
vector<int> E[maxn];
int g[maxn][maxn];
bool vis[maxn];
int mc[maxn];

bool dfs(int x)
{
    for (int i = 0; i < E[x].size(); i ++ )
    {
        int y = E[x][i];
        if (!vis[y])
        {
            vis[y] = true;
            if (!mc[y] || dfs(mc[y]))
            {
                mc[x] = y;
                mc[y] = x;
                return true;
            }
        }
    }
    return false;
}

int main()
{
    ios::sync_with_stdio(false);
    cin >> n >> m;
    for (int i = 1; i <= m; i ++ )
    {
        int a, b;
        cin >> a >> b;
        E[a].push_back(b);
        E[b].push_back(a);
    }
    int ans = 0;
    for (int i = 1; i <= n >> 1; i ++ )
    {
        if (!mc[i])
        {
            memset(vis, 0, sizeof(vis));
            if(dfs(i)) ++ ans;
        }
    }
    cout << ans << endl;
    return 0;
}
#include <bits/stdc++.h>
using namespace std;
const int N = 505*2, M= N * N;
struct E{
    int next,to;
}e[M];
//mc:表示每個點所匹配到的另一個點match
//vis:Y集元素是否被訪問過
int cnt,ihead[N],mc[N];
bool vis[N];
void add(int x,int y){
    e[++cnt].next = ihead[x];
    e[cnt].to = y;
    ihead[x] = cnt;
}
//匈牙利演算法
//x:x集上的點,從當前點出發找增廣路
//返回值:若找到增廣路則返回true,否則返回false
bool dfs(int x){
    for(int i=ihead[x]; i; i=e[i].next){
        int y = e[i].to;
        if(!vis[y]){//如果找到一個Y集上的點沒有標記
            vis[y] = true;//標記該點
            //如果y是沒有匹配點的,說明找到了一條增廣路;或者說遞迴查詢y的匹配點,得到了一條增廣路
            if(mc[y] == 0 || dfs(mc[y])){
                //找到了增廣路,更新mc陣列
                mc[x] = y;
                mc[y] = x;
                return true;
            }
        }
    }
    return false;
}
int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        int a,b;
        scanf("%d%d",&a,&b);
        add(a,b);
        add(b,a);
    }
    int ans = 0;
    for(int i=1; i<=n/2; ++i)
        if(!mc[i]){
            //如果x集中的第i個點沒有匹配到Y集上的點,則從這個點出發尋找增廣路
            memset(vis, 0, sizeof(bool) * (n + 1));
            //將陣列置為0
            if(dfs(i))
                ++ans;//如果找到,答案直接+1
        }
    printf("%d",ans);
 	return 0;   
}

相關文章