※ 글쓴이는 취미로 코딩을 익혀보는 사람이라 정확하지 않은 내용을 담고 있을 수 있다 ※

 

이번에 볼 문제는 백준 1727번 문제인 커플 만들기이다.
문제는 아래 링크를 확인하자.

https://www.acmicpc.net/problem/1727

 

남자와 여자를 이어줄 때 둘의 성격의 차이를 "비용"이라 부르겠다.

 

먼저 남자들과 여자들의 성격수치를 각각 오름차순으로 정렬하자. 이때, k명의 남자와 k명의 여자를 고른 경우 이들을 모두 이어주면서 그 비용을 최소화하는 방법은 성격수치 순서대로 이어주는 것임을 관찰하자. (증명은 exchange argument로 할 수 있다.)

 

위 관찰을 이용하면, pq이라 할 때 p번째 남자까지 봤을 때 q번째 여자까지 비용을 최소로 매칭시킬 때의 비용은 (1) q번째 여자를 p번째 남자에게 매칭시키거나, (2) 그렇지 않은 두 가지 경우가 있다는 점을 이용해 점화식을 세울 수 있게 된다. 여기서 (1)의 값을 구하고자 할 때 q1번째 여자를 p1이하번째 남자에게 매칭시킬 때의 최소 비용을 알아야 하는데, 이 또한 메모이제이션을 통해 반복계산을 줄여 충분히 빠르게 구할 수 있음을 관찰하자.

 

아래는 제출한 소스코드이다.

#include <iostream>
#include <algorithm>
using namespace std;

int N, M;
int mn[1001][1001], dp[1001][1001]; bool mvisited[1001][1001], visited[1001][1001];// [N][M]이 마지막 매칭인 최솟값
int A[1001], B[1001];

int func(int n, int m);

int mnfunc(int n, int m) {
	if (n < m) return 0x3f3f3f3f;
	if (!m) return 0;
	int &ret = mn[n][m];
	if (mvisited[n][m]) return ret;
	mvisited[n][m] = 1;
	ret = func(n, m);
	ret = min(ret, mnfunc(n - 1, m));
	return ret;
}

int func(int n, int m) {
	int &ret = dp[n][m];
	if (visited[n][m]) return dp[n][m];
	visited[n][m] = 1;
	ret = mnfunc(n - 1, m - 1) + abs(A[n] - B[m]);
	return ret;
}

int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);

	cin >> N >> M;
	for (int i = 1; i <= N; i++) cin >> A[i];
	sort(A + 1, A + N + 1);
	for (int j = 1; j <= M; j++) cin >> B[j];
	sort(B + 1, B + M + 1);

	if (N < M) swap(N, M), swap(A, B);
	cout << mnfunc(N, M);
}

 

처음 이 문제를 접근할 때의 글쓴이가 했던 생각을 같이 남겨둔다.

 

글쓴이는 처음에 이 문제를 성격수치가 x인 남자와 y인 여자를 짝지어줄 때의 비용을 xy의 절댓값으로 나타낼 때, minimum weight maximal bipartite matching의 그 가중치 총합을 구하는 문제로 보았다. 이 점에 초점을 맞춰 MCMF로 문제를 해결하려고 시도했으나, 시간초과로 해결하지 못했다. 다만, 이후에 몇몇 성질을 이용해 불필요한 간선 일부를 줄인 그래프 모델링과 MCMF로 뚫는 데에 성공하기는 했다.

 

헝가리안 알고리즘(Hungarian algorithm; Kuhn-Munkres Algorithm)은 구현해본 적이 없어 확인하지 않았는데 (안될 것 같지만) 이걸로도 풀릴까...?

 

BOJ Random Defense #10 (실패: 제한시간초과)

728x90

'BOJ' 카테고리의 다른 글

[BOJ 23000 // C++] L Shaped Plots  (0) 2024.06.01
[BOJ 9911 // C++] ERP  (0) 2024.05.31
[BOJ 22887 // C++] Reversort Engineering  (0) 2024.05.29
[BOJ 9176 // C++] 메르센 합성수  (0) 2024.05.28
[BOJ 7146 // C++] 데이터 만들기 7  (0) 2024.05.27

+ Recent posts