처음 이 문제를 접했을 때에는 '혹시 쌍둥이 소수' 문제일까 하고 봤었네요. 소수쌍이 아니라 합이 소수가 되는 숫자들의 합 이야기입니다. 짝수인 N개가 주어지면, 합이 소수가 되는 쌍으로 모두 묶을 수 있다면, 첫번째 수와 묶일 수 있는 수들의 리스트를 내는 문제입니다. 난이도는 Platinum III이지만, 난이도보다는 쉬운 문제입니다. 물론 네트워크 플로우 알고리즘을 알고 있을 때에 한합니다. DFS 알고리즘으로도 풀 수 있지만, 그렇게 하면 시간초과가 납니다.

아래는 해당 문제의 링크입니다.
https://www.acmicpc.net/problem/1017
1017번: 소수 쌍
지민이는 수의 리스트가 있을 때, 이를 짝지어 각 쌍의 합이 소수가 되게 하려고 한다. 예를 들어, {1, 4, 7, 10, 11, 12}가 있다고 하자. 지민이는 다음과 같이 그룹지을 수 있다. 1 + 4 = 5, 7 + 10 = 17, 11 + 12 = 23 또는 1 + 10 = 11, 4 + 7 = 11, 11 + 12 = 23 수의 리스트가 주어졌을 때, 지민이가 모든 수를 다 짝지었을 때, 첫 번째 수와 어떤 수를 짝지었는지 오름차순으로 출력하는
www.acmicpc.net
이 문제에서는 소수를 빨리 찾는 방법이 관건입니다. 리스트에 있는 수들의 50개이므로, 첫번째수와 연결되는 두번째 수를 선택하고 나머지에 대해서 소수쌍이 되는지 검사하면 됩니다. 미리 매칭 테이블을 만들어놓아서 한다면, 최대
알고리즘은 간단합니다.
첫번째 수는 당연히 필요한 것이고, 두번째 수를 차례대로 선택한 후, 이 합이 소수이면, 나머지 수들에 대해서는 네트워크플로우를 이용해서 소수쌍으로 모든 수들이 참여가능한지 판단합니다. 그렇게 판단이 되면 두번째 수를 출력하고 이 과정을 반복하면 됩니다.

제가 작성한 소스입니다.
//----------------------------------------------------------
// baekjoon #1017 - Prime Pairs
// - by Aubrey Choi
// - created at 2019-05-20
//----------------------------------------------------------
#include <stdio.h>
#include <memory.h>
static unsigned char primes[] = {
0xac,0x28,0x8a,0xa0,0x20,0x8a,0x20,0x28, 0x88,0x82,0x08,0x02,0xa2,0x28,0x02,0x80,
0x08,0x0a,0xa0,0x20,0x88,0x20,0x28,0x80, 0xa2,0x00,0x08,0x80,0x28,0x82,0x02,0x08,
0x82,0xa0,0x20,0x0a,0x20,0x00,0x88,0x22, 0x00,0x08,0x02,0x28,0x82,0x80,0x20,0x88,
0x20,0x20,0x02,0x02,0x28,0x80,0x82,0x08, 0x02,0xa2,0x08,0x80,0x80,0x08,0x88,0x20,
0x00,0x0a,0x00,0x20,0x08,0x20,0x08,0x0a, 0x02,0x08,0x82,0x82,0x20,0x0a,0x80,0x00,
0x8a,0x20,0x28,0x00,0x22,0x08,0x08,0x20, 0x20,0x80,0x80,0x20,0x88,0x80,0x20,0x02,
0x22,0x00,0x08,0x20,0x00,0x0a,0xa0,0x28, 0x80,0x00,0x20,0x8a,0x00,0x20,0x8a,0x00,
0x00,0x88,0x80,0x00,0x02,0x22,0x08,0x02, 0x80,0x08,0x82,0x80,0x20,0x00,0x22,0x28,
0x80,0x82,0x00,0x0a,0xa0,0x20,0x00,0x80, 0x28,0x82,0x20,0x20,0x08,0x02,0x00,0x80,
0x02,0x08,0x08,0x20,0x08,0x02,0x02,0x20, 0x82,0xa0,0x20,0x00,0x02,0x08,0x00,0xa0,
0x08,0x0a,0xa2,0x08,0x80,0x82,0x00,0x00, 0x00,0x00,0x82,0x20,0x20,0x00,0x80,0x00,
0x02,0x80,0x28,0x82,0x80,0x28,0x08,0x80, 0x00,0x8a,0x22,0x08,0x80,0x00,0x08,0x08,
0x80,0x20,0x82,0x80,0x08,0x88,0x00,0x20, 0x82,0x22,0x28,0x08,0x20,0x00,0x00,0x82,
0x28,0x00,0x00,0x20,0x0a,0x20,0x00,0x0a, 0x20,0x20,0x08,0x82,0x00,0x00,0x82,0x28,
0x00,0x02,0x08,0x80,0x80,0x00,0x80,0x00, 0x20,0x88,0xa2,0x00,0x02,0x20,0x08,0x02,
0x00,0x28,0x00,0xa0,0x00,0x00,0x20,0x08, 0x08,0xa2
};
inline bool isprime(int p) { return (bool)((primes[p / 8] >> (p % 8)) & 1); }
char b[25], v[25], adj[25][26]; int n;
bool dfs(int s)
{
v[s] = 1;
for(int i = 1; i <= adj[s][0]; i++)
{
int t = adj[s][i];
if(b[t] == -1 || (v[b[t]] == 0 && dfs(b[t])))
{
b[t] = s;
return true;
}
}
return false;
}
bool checkmatch(int s, int n)
{
memset(b, 0xff, sizeof(b));
b[s] = 0;
for(int i = 1; i < n; i++)
{
memset(v, 0, sizeof(v));
v[0] = 1;
if(!dfs(i)) return false;
}
return true;
}
int main()
{
int l[25], r[25], lcount = 1, rcount = 0, t, i, j;
scanf("%d%d",&n,&l[0]);
for(i=1;i<n;i++) { scanf("%d",&t); if((t+l[0])%2) r[rcount++]=t; else l[lcount++]=t; }
if(lcount != rcount) { puts("-1"); return 0; }
// check primes between elements.
for(i = 0; i < lcount; i++)
{
int count = 0;
for(j = 0; j < lcount; j++)
{
if(isprime(l[i] + r[j])) adj[i][++count] = j;
}
adj[i][0] = count;
if(!count) { puts("-1"); return 0; }
}
int ans[100], count = 0;
for(i=1;i<=adj[0][0];i++)
{
int s = adj[0][i];
if(checkmatch(s, lcount))
{
int last = count++;
while(last > 0 && ans[last-1] > r[s])
{
ans[last] = ans[last-1];
last--;
}
ans[last] = r[s];
}
}
if(count == 0) { puts("-1"); return 0; }
for(i = 0; i < count; i++) printf("%d ", ans[i]); putchar('\n');
}
'Programming > BOJ' 카테고리의 다른 글
백준 #1019 책 페이지 (0) | 2019.12.25 |
---|---|
[C/C++] 백준 #1018 체스판 다시 칠하기 (0) | 2019.12.24 |
[C/C++] 백준 #1016 제곱 ㄴㄴ수 (0) | 2019.12.24 |
[C/C++] 백준 #1015 수열 정렬 (0) | 2019.12.23 |
[C/C++] 백준 #1012 유기농 배추 (0) | 2019.12.22 |
댓글