티스토리 뷰

반응형

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

 

1017번: 소수 쌍

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

www.acmicpc.net

필요한 배경지식

  • 이분매칭
  • 소수판정 - (에라토스테네스의 체)

 

 

문제 해결 방법

 

이분매칭을 이용하면 됩니다.

 

우선 두 수를 더한 값이 소수일때 두 수를 연결하는 간선을 추가하여 그래프를 만들어야 합니다.

그 다음 이분매칭을 하여 매칭된 쌍의 개수가 N/2개일때 첫 번째 수와 짝지어진 수를 출력하면 됩니다.

 

소수를 판정할 때에는 두 수를 더한 값이 최대 2000이기 때문에 에라토스테네스의 체를 이용하여

전처리 후 소수를 판정했습니다.

 

이분매칭할때 주의할 점은 한 집단 내에서 매칭을 해야하기 때문에 매칭할때 간선을 양쪽으로 확인해 주어야 합니다.

(예를들어 양방향으로 확인하지 않으면, 1과 4가 매칭되었는데 4와 7이 매칭되어 4가 한번 더 매칭될 수 있음)

 

또한, 첫번째 수와 짝지어진 수를 확인해야 하기 때문에 첫 번째 수를 포함하여 미리 한 쌍을 매칭해 주고 매칭된 쌍의 총 개수가 N/2개인지 확인해 주어야 합니다.

 

 

 

 

 

전체 코드

#include<bits/stdc++.h>
#define MAX 2000
using namespace std;

int N;
int arr[50]{};
int sieve[MAX+1];
vector<int> adj[51]{};
int A[51]{};
int B[51]{};
bool vi[51]{};

void find_prime(){
    memset(sieve, -1, sizeof(sieve));
    for(int i=2; i*i<=MAX; ++i)
        if(sieve[i] == -1)
            for(int j=i*i; j<=MAX; j+=i)
                if(sieve[j] == -1)
                    sieve[j] = i;
}

bool dfs(int cur){
    if(vi[cur]) return false;
    vi[cur] = true;
    for(auto next : adj[cur]){
        if(B[next]==-1 || dfs(B[next])){
            A[cur] = next;
            B[next] = cur;
            A[next] = cur; // 양쪽으로 간선 확인
            B[cur] = next; 
            return true;
        }
    }
    return false;
}

int main() {
    ios_base::sync_with_stdio(0);
    cin.tie(0);
    find_prime();
    cin>>N;
    int t;
    for(int i=0; i<N; i++) {
        cin>>arr[i];
    }
    for(int i=0; i<N; i++){
        for(int j=i+1; j<N; j++){
            if(sieve[arr[i]+arr[j]]==-1) {
                adj[i].push_back(j);
                adj[j].push_back(i);
            }
        }
    }

    vector<int> ans;
    for(auto next : adj[0]){
        memset(A, -1, sizeof(A));
        memset(B, -1, sizeof(B));
        int res = 1;
        // 미리 한쌍 매칭
        A[0] = next;
        B[next] = 0;
        A[next] = 0; // 양쪽으로 간선 확인
        B[0] = next;
        for(int i=1; i<N; i++){
            if(A[i]==-1){
                memset(vi, 0, sizeof(vi));
                vi[0] = true;
                vi[next] = true;
                if(dfs(i)) res++;
            }
        }
        if(res==N/2) ans.push_back(arr[next]);
    }
    if(ans.size()==0) cout<<-1;
    else {
        sort(ans.begin(), ans.end());
        for(auto val : ans) cout<<val<<' ';
    }
}

 

 

 

반응형

'알고리즘 공부 > 문제풀이' 카테고리의 다른 글

백준 1256번 - 사전  (0) 2022.01.12
백준 14226번 - 이모티콘  (0) 2021.07.10
백준 4991번 - 로봇 청소기  (0) 2021.06.01
백준 17142번 - 연구소 3  (0) 2021.05.31
백준 2342번 - Dance Dance Revolution  (0) 2021.05.31
댓글
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함