-
1017번 : 소수 쌍알고리즘/백준(acmicpc.net) 문제풀이 2022. 1. 31. 16:11반응형
https://www.acmicpc.net/problem/1017
1017번: 소수 쌍
지민이는 수의 리스트가 있을 때, 이를 짝지어 각 쌍의 합이 소수가 되게 하려고 한다. 예를 들어, {1, 4, 7, 10, 11, 12}가 있다고 하자. 지민이는 다음과 같이 짝지을 수 있다. 1 + 4 = 5, 7 + 10 = 17, 11 +
www.acmicpc.net
집합에 속한 임의의 원소 두개의 합이 소수가 되도록 모두 짝지었을 때 첫 번째 원소와 짝지은 원소들을 오름차순으로 출력하는 문제다.
아이디어, 구현 :
네트워크 플로우(이분매칭)으로 해결할 수 있었다. 하지만 조금 특이한 방식으로 해결했다.
먼저, 모든 수를 두개로 늘려서 짝지을 첫번째 원소, 짝지을 두번째 원소로 나누었다. 첫 번째 원소는 제외하고.
즉 첫 번째 그룹에는 N-1개, 두번째 그룹에도 똑같이 N-1개가 있고, src에서 첫 번째 그룹으로, 첫 번째 그룹에서 두 번째 그룹으로, 두 번째 그룹에서 snk로 가도록 이분매칭 형태를 만들었다.어떤 수 a와 어떤 수 b의 합이 소수일 때 첫번째 그룹에서 두번째그룹으로 가는 간선을 추가해주었다. 소수 판정을 에라토스테네스의 체와 이분탐색으로 해결했다. (지금 생각해보니 에라토스테네스의 체에서 바로 소수판정을 해도 괜찮을 것 같다.) 아무튼 간선을 다 추가한 다음, src->첫번째그룹에 있는 첫번째 수 -> 두번째그룹에 있는 다른 수->snk 이런 경로를 하나씩 추가한 후 max flow를 돌려서 N-1이 나오면 답으로 추가했다.
상어의 저녁식사 [https://www.acmicpc.net/problem/1671] 문제랑 동일하게 해결했다.
다른 분들은 짝수그룹, 홀수그룹으로 나눠서 dfs를 돌렸다. 그것도 좋은 방법인 것 같다.
코드 :
#include <bits/stdc++.h> using namespace std; const int MN=50; const int INF=987654321; int arr[MN]; vector<int> G[MN*2+2]; int c[MN*2+2][MN*2+2], f[MN*2+2][MN*2+2], p[MN*2+2]; vector<int> prime; int sieve[3000]; void init(){ for(int i=0; i<MN*2+2; ++i){ for(int j=0; j<MN*2+2; ++j){ f[i][j]=0; } } } int maxFlow(int src, int snk){ int ret=0; while(1){ fill(p, p+MN*2+2, -1); p[src]=src; queue<int> q; q.push(src); while(!q.empty() && p[snk]==-1){ int cur=q.front(); q.pop(); for(auto nxt:G[cur]){ if(c[cur][nxt]-f[cur][nxt]>0 && p[nxt]==-1){ q.push(nxt); p[nxt]=cur; } } } if(p[snk]==-1) break; int flow=INF; for(int i=snk; i!=src; i=p[i]){ flow=min(flow, c[p[i]][i]-f[p[i]][i]); } for(int i=snk; i!=src; i=p[i]){ f[p[i]][i]+=flow; f[i][p[i]]-=flow; } ret+=flow; } return ret; } int main(){ int N; cin>>N; for(int i=0; i<N; ++i){ cin>>arr[i]; } for(int i=2; i*i<3000; ++i){ if(sieve[i]) continue; for(int j=i*i; j<3000; j+=i){ sieve[j]=1; } } for(int i=2; i<3000; ++i){ if(!sieve[i]) prime.push_back(i); } int src=MN*2, snk=MN*2+1; for(int i=1; i<N; ++i){ G[src].push_back(i); G[i].push_back(src); c[src][i]=1; G[i+MN].push_back(snk); G[snk].push_back(i+MN); c[i+MN][snk]=1; for(int j=1; j<N; ++j){ if(i==j) continue; if(binary_search(prime.begin(), prime.end(), arr[i]+arr[j])){ // cout << arr[i] << ", " << arr[j] << '\n'; G[i].push_back(j+MN); G[j+MN].push_back(i); c[i][j+MN]=1; } } } G[src].push_back(0); G[0].push_back(src); c[src][0]=1; vector<int> res; for(int i=1; i<N; ++i){ G[0].push_back(i+MN); G[i+MN].push_back(0); if(binary_search(prime.begin(), prime.end(), arr[0]+arr[i])){ c[0][i+MN]=1; init(); int temp=maxFlow(src,snk); // cout << "i : " << i << ", temp : " << temp << '\n'; if(temp==N-1){ res.push_back(arr[i]); } c[0][i+MN]=0; } } if(res.size()==0) cout << "-1\n"; else{ sort(res.begin(), res.end()); for(auto it:res) cout << it << ' '; cout << '\n'; } }
반응형'알고리즘 > 백준(acmicpc.net) 문제풀이' 카테고리의 다른 글
2123번 : 인간 탑 쌓기 (0) 2022.01.29 1422번 : 숫자의 신 (0) 2022.01.22 1369번 : 배열값 (0) 2022.01.22 1154번 : 팀 편성 (0) 2022.01.16 1131번 : 숫자 (0) 2022.01.14