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

 

이번에 볼 문제는 백준 1536번 문제인 Dance, Dance이다.
문제는 아래 링크를 확인하자.

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

 

1536번: Dance, Dance

첫째 줄에 남자의 수 N과, K가 주어진다. N은 50보다 작거나 같은 자연수이고, K는 0보다 크거나 같고 50보다 작거나 같은 자연수이다. 둘째 줄에는 첫 번째 남학생과 첫 번째 여학생이 서로 좋아하

www.acmicpc.net

남자 N명과 여자 N명이 각자 최대 K명까지 "서로 좋아하지 않는" 사람과 춤을 출 수 있고, 한번 춤췄던 쌍은 다시 춤을 추지 못할 때 춤을 최대 몇 번 출 수 있는가를 구하는 문제이다.

 

춤을 M번 출 수 있는지 판단하는 결정문제를 해결할 수 있다면, 이분탐색을 통해 답을 구해낼 수 있을 것이다. 따라서, M이 주어졌을 때 춤을 M번 출 수 있을지를 판단하는 방법을 살펴보자.

 

각 남자와 여자는 서로 좋아하는 사람과는 춤을 추는 데에 제한이 없지만 그렇지 않은 경우는 각자 K번 이하가 되어야 한다. 그러므로 제한없이 춤을 출 수 있는 횟수와 제한에 포함되는 횟수를 분리하여 아래와 같은 구조의 네트워크 그래프를 만들어 max flow가 M*N과 일치하는지를 살피는 것으로 문제를 해결할 수 있다.

 

source --<가중치: M>-- 각 남자 노드 --<가중치: INF(서로 좋아하는 쌍), K(그렇지 않은 쌍)>-- 각 남자의 좋아하는/그렇지 않은 사람과 춤추는 것을 체크하기 위한 노드 --<가중치: 1>-- 각 여자의 좋아하는/그렇지 않은 사람과 춤추는 것을 체크하기 위한 노드  --<가중치: INF(서로 좋아하는 쌍), K(그렇지 않은 쌍)>-- 각 여자 노드 --<가중치: M>-- sink

 

글쓴이는 dinic 알고리즘을 이용하여 문제를 해결하였다.

 

아래의 구현에서 각 노드의 인덱스는 다음과 같은 의미이다:

0: source

0*N+k+1: k번 남자 노드

1*N+k+1: k번 남자가 좋아하는 사람과 춤추는 것을 체크하기 위한 노드

2*N+k+1: k번 남자가 좋아하지 않은 사람과 춤추는 것을 체크하기 위한 노드

3*N+k+1: k번 여자 노드

4*N+k+1: k번 여자가 좋아하는 사람과 춤추는 것을 체크하기 위한 노드

5*N+k+1: k번 여자가 좋아하지 않은 사람과 춤추는 것을 체크하기 위한 노드

6*N+1: sink

 

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

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

int N, K;
string board[50];
vector<int> G[302];
int edge[302][302];

int level[302];
bool bfs() {
	memset(level, 0, sizeof(level));
	level[0] = 1;
	queue<int> que;
	que.push(0);
	while (!que.empty()) {
		int current = que.front(); que.pop();
		for (auto node : G[current]) {
			if (level[node]) continue;
			if (edge[current][node]) {
				level[node] = level[current] + 1;
				que.push(node);
			}
		}
	}

	return level[6 * N + 1];
}

int turn[302];
int dfs(int current, int flow) {
	if (current == 6 * N + 1) return flow;
	int cursize = G[current].size();
	for (int& i = turn[current]; i < cursize; i++) {
		int node = G[current][i];
		if (edge[current][node] && level[node] == level[current] + 1) {
			int f = dfs(node, min(edge[current][node], flow));
			if (f) {
				edge[current][node] -= f;
				edge[node][current] += f;
				return f;
			}
		}
	}
	return 0;
}

bool func (int X) {
	memset(edge, 0, sizeof(edge));
	for (int r = 0; r < N; r++) {
		edge[0][r + 1] = X;
		edge[r + 1][N + r + 1] = 1000000007;
		edge[r + 1][2 * N + r + 1] = K;
		edge[3 * N + r + 1][6 * N + 1] = X;
		edge[4 * N + r + 1][3 * N + r + 1] = 1000000007;
		edge[5 * N + r + 1][3 * N + r + 1] = K;
		for (int c = 0; c < N; c++) {
			if (board[r][c] == '1') edge[N + r + 1][4 * N + c + 1] = 1;
			else edge[2 * N + r + 1][5 * N + c + 1] = 1;
		}
	}

	int flow = 0;

	while (bfs()) {
		memset(turn, 0, sizeof(turn));
		int f;
		while (f = dfs(0, 1000000007)) flow += f;
	}

	return flow == N * X;
}

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

	cin >> N >> K;
	for (int i = 0; i < N; i++) cin >> board[i];
	for (int r = 0; r < N; r++) {
		G[0].emplace_back(r + 1);
		G[r + 1].emplace_back(0);
		G[r + 1].emplace_back(N + r + 1);
		G[N + r + 1].emplace_back(r + 1);
		G[r + 1].emplace_back(2 * N + r + 1);
		G[2 * N + r + 1].emplace_back(r + 1);
		G[6 * N + 1].emplace_back(3 * N + r + 1);
		G[3 * N + r + 1].emplace_back(6 * N + 1);
		G[3 * N + r + 1].emplace_back(4 * N + r + 1);
		G[4 * N + r + 1].emplace_back(3 * N + r + 1);
		G[3 * N + r + 1].emplace_back(5 * N + r + 1);
		G[5 * N + r + 1].emplace_back(3 * N + r + 1);
		for (int c = 0; c < N; c++) {
			if (board[r][c] == '1') {
				G[N + r + 1].emplace_back(4 * N + c + 1);
				G[4 * N + c + 1].emplace_back(N + r + 1);
			}
			else {
				G[2 * N + r + 1].emplace_back(5 * N + c + 1);
				G[5 * N + c + 1].emplace_back(2 * N + r + 1);
			}
		}
	}

	int L = 0, R = 50;
	while (L < R) {
		int mid = (L + R) / 2 + 1;
		if (func(mid)) L = mid;
		else R = mid - 1;
	}

	cout << L;
}
728x90

'BOJ' 카테고리의 다른 글

[BOJ 1516 // C++] 게임 개발  (0) 2022.01.05
[BOJ 15337 // C++] Starting a Scenic Railroad Service  (0) 2022.01.04
[BOJ 17400 // C++] 깃발춤  (0) 2022.01.02
[BOJ 10976 // C++] 피난  (0) 2022.01.01
[BOJ 1739 // C++] 도로 정비하기  (0) 2021.12.31

+ Recent posts