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

 

이번에 볼 문제는 백준 1017번 문제인 소수 쌍이다.
문제는 아래 링크를 확인하자.

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

 

1017번: 소수 쌍

지민이는 수의 리스트가 있을 때, 이를 짝지어 각 쌍의 합이 소수가 되게 하려고 한다. 예를 들어, {1, 4, 7, 10, 11, 12}가 있다고 하자. 지민이는 다음과 같이 그룹지을 수 있다. 1 + 4 = 5, 7 + 10 = 17, 11

www.acmicpc.net

2를 제외한 모든 소수는 홀수이고 서로 다른 두 자연수의 합은 2가 될 수 없다는 점을 눈여겨보자.

두 수의 합이 소수가 되게 하려면 수 하나는 짝수에서, 다른 수 하나는 홀수에서 골라야한다는 점을 알 수 있다.

 

각 수를 노드로 하고, 합이 소수가 되는 두 수(하나는 홀수, 하나는 짝수일 수밖에 없다) 사이에 에지를 그으면 이분그래프(bipartite graph)를 하나 얻을 수 있다. 첫 노드와 이어지는 노드를 하나하나 고정해서 이분매칭을 구해보자.

 

이분매칭의 시간복잡도가 O(VE) = O(N^3)이고 노드를 하나하나 고정하는 경우가 최악의 경우 N가지 있으므로 시간복잡도는 O(N^4)이고, 문제에서 주어진 N의 크기가 50이므로 문제를 해결할 수 있다. (글쓴이는 처음에 이게 통과 안될거라고 잘못 짐작하여 생각을 오래 했다...)

 

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

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

bool sieve[2000];

vector<int> oddnums, evennums;
vector<int> G[1001];
int matching[1001];
int visited[1001];
int fixednum;

int bipartite(int current) {
	if (visited[current]) return 0;
	visited[current] = 1;
	if (current == fixednum) return 0;
	for (auto node : G[current]) {
		if (node == fixednum) continue;
		if (matching[node] == 0) {
			matching[node] = current;
			return 1;
		}
		else if (bipartite(matching[node])) {
			matching[node] = current;
			return 1;
		}
	}
	return 0;
}

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

	sieve[0] = sieve[1] = 1;
	for (int i = 2; i < 44; i++) {
		if (sieve[i]) continue;
		for (int j = i * i; j < 2000; j += i) {
			sieve[j] = 1;
		}
	}

	int N; cin >> N;
	int first; cin >> first;
	for (int i = 1; i < N; i++) {
		int x; cin >> x;
		if (x & 1) oddnums.emplace_back(x);
		else evennums.emplace_back(x);
	}

	for (auto o : oddnums) {
		for (auto e : evennums) {
			if (sieve[o + e]) continue;
			G[o].emplace_back(e);
		}
	}

	vector<int> ans;

	if (first & 1) {
		for (auto e : evennums) {
			if (sieve[first + e]) continue;
			memset(matching, 0, sizeof(matching));
			fixednum = e;
			int cnt = 0;
			for (auto o : oddnums) {
				memset(visited, 0, sizeof(visited));
				cnt += bipartite(o);
			}

			if (cnt + 1 == N / 2) ans.emplace_back(e);
		}
	}
	else {
		for (auto o : oddnums) {
			if (sieve[first + o]) continue;
			memset(matching, 0, sizeof(matching));
			fixednum = o;
			int cnt = 0;
			for (auto o : oddnums) {
				memset(visited, 0, sizeof(visited));
				cnt += bipartite(o);
			}

			if (cnt + 1 == N / 2) ans.emplace_back(o);
		}
	}

	sort(ans.begin(), ans.end());

	if (ans.empty()) cout << -1;
	else {
		for (auto x : ans) cout << x << ' ';
	}
}
728x90

'BOJ' 카테고리의 다른 글

[BOJ 2472 // C++] 체인점  (0) 2021.09.25
[BOJ 1615 // C++] 교차개수세기  (0) 2021.09.24
[BOJ 10282 // C++] 해킹  (0) 2021.09.22
[BOJ 5721 // C++] 사탕 줍기 대회  (0) 2021.09.21
[BOJ 22865 // C++] 가장 먼 곳  (0) 2021.09.20

+ Recent posts