ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 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

    댓글

Designed by Tistory.