알고리즘 모음(C++)

백준 11375 - 열혈강호(C++) 본문

백준

백준 11375 - 열혈강호(C++)

공대생의 잡다한 사전 2023. 2. 11. 17:33

문제 링크입니다. https://www.acmicpc.net/problem/11375

 

11375번: 열혈강호

강호네 회사에는 직원이 N명이 있고, 해야할 일이 M개가 있다. 직원은 1번부터 N번까지 번호가 매겨져 있고, 일은 1번부터 M번까지 번호가 매겨져 있다. 각 직원은 한 개의 일만 할 수 있고, 각각

www.acmicpc.net

이분 매칭을 사용하는 문제입니다.

이분 그래프에서 두 그룹을 X, Y그룹이라고 할 때, 모든 경로의 방향이  X -> Y인 그래프의 최대 유량을 구하는 것이 이분 매칭입니다. 

문제에서 볼 수 있듯이, 이분 매칭을 통해 구하고자 하는 것은 최대 매칭 수입니다. 

이때 매칭한다는 것은 1대 1함수와 같이 하나의 정점이 다른 그룹의 하나의 정점만을 점유하고 있는 상태를 말합니다.

 

이분 매칭을 구성하는 핵심 코드입니다.

bool dfs(int start){
    if(check[start]) return false;
    check[start] = true;
    for(int i = 0; i < Match[start].size(); i++){
        int x = Match[start][i];
        if(b_match[x] == -1 || dfs(b_match[x])){
            a_match[start] = x;
            b_match[x] = start;
            return true;
        }
    }
    return false;
}

start에는 1 부터 N까지, 한 그룹의 정점이 순서대로 입력됩니다.

check 배열을 통해, 찾으려는 정점이 이전에 다른 점과 연결되어 있는지를 확인합니다. 

자신과 연결된 정점을 연결하는 과정에서,

 

1. 내가 매칭하려는 점이 다른 점과 연결이 되어있나?

2. 매칭하려는 점과 연결된 정점이 다른 정점과 연결될 수 있나? 

 

두 가지를 확인합니다. 2번을 확인하는 이유는 순서대로 정점을 탐색하기 때문에, 현재 매칭하려는 점이 다른 점과 연결되어 있다면 현재 정점보다 앞의 순서일 것입니다. 앞 순서의 정점을 다른 점에 다시 매칭할 수 있다면, 현재 정점을 이을 수 있음으로 더 많을 수를 매칭할 수 있게 됩니다. 

두 조건 중 하나만 만족한다면, 정점들을 매칭해줍니다. 

 

해당 DFS 과정을 1~N번 정점까지 넣어주면서 확인합니다. 그 과정에서 더이상 매칭할 수 없는 경우가 있을 것 입니다.

1. 자신보다 앞선 정점을 다른 정점과 매칭할 수 없는 경우

2. 더 이상 정점을 매칭할 수 없는 경우

해당 경우에는 DFS가 true의 값을 return하지 못함으로 이분 매칭이 끝나게 됩니다.

 

마지막에 Size를 출력하면서 최대 매칭 수를 구해주면 됩니다.

 

자세한 것은 코드를 참고해주세요

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstring>
#include <vector>
#include <algorithm>
#include <queue>
#include <cmath>
#include <cstdio>
#include <string>
#include <deque>
#include <stack>
#include <map>
#define LL long long
#define pp pair<int, int>
#define F first
#define S second

using namespace std;

int N, M;
vector<int> Match[1011];
vector<int> a_match, b_match;
bool check[1011];

bool dfs(int start){
    if(check[start]) return false;
    check[start] = true;
    for(int i = 0; i < Match[start].size(); i++){
        int x = Match[start][i];
        if(b_match[x] == -1 || dfs(b_match[x])){
            a_match[start] = x;
            b_match[x] = start;
            return true;
        }
    }
    return false;
}

void solve(){
    a_match = vector<int>(N+1, -1);
    b_match = vector<int>(M+1, -1);
    int size = 0;
    for(int i = 1; i <= N; i++){
        memset(check, false, sizeof(check));
        if(dfs(i)) size++;
    }
    cout << size;
}

int main() {
    cin.tie(0);
	cout.tie(0);
	cin >> N >> M;
	for(int i = 1; i <= N; i++){
	    int n;
	    cin >> n;
	    for(int j = 1; j <= n; j++){
	        int x;
	        cin >> x;
	        Match[i].push_back(x);
	    }
	}
	solve();
	return 0;
}

 

 

질문 및 조언은 댓글을 남겨주세요

'백준' 카테고리의 다른 글

백준 11376 - 열혈강호 2(C++)  (0) 2023.02.11
백준 2188 - 축사 배정(C++)  (0) 2023.02.11
백준 2143 - 두 배열의 합(C++)  (0) 2023.02.09
백준 1562 - 계단 수(C++)  (0) 2023.02.08
백준 9086 - 문자열(C++)  (0) 2023.02.08