Today's special moments become memories of tomorrow.

알고스팟

[알고스팟] PICNIC

lotus lee 2023. 3. 18. 14:17

https://algospot.com/judge/problem/read/PICNIC

 

algospot.com :: PICNIC

소풍 문제 정보 문제 안드로메다 유치원 익스프레스반에서는 다음 주에 율동공원으로 소풍을 갑니다. 원석 선생님은 소풍 때 학생들을 두 명씩 짝을 지어 행동하게 하려고 합니다. 그런데 서로

algospot.com

 


 

 

알고리즘

학생들을 짝지어 주되, 짝이 된 학생끼리는 서로 친구이도록 짝을 지어줘야하는 문제이다.

친구인지 아닌지 여부는 미리 주어진다.

 

학생의 수가 총 4명이고 n = 4,

친구쌍이 총 6쌍이고 다음과 같을 때 m = 6

(0,1) (1,2) (2,3) (3,0) (0,2) (1,3)가 서로 친구인 쌍이다.

4 6 
0 1 1 2 2 3 3 0 0 2 1 3 

 

0번 학생부터 4번 학생까지 완전탐색으로 짝을 지어준다. 

이때 중요한 점은, 자기번호보다 번호가 큰 학생들 중에 친구인 학생과 짝을 지어준다.

 

k번 학생의 짝을 지어줄 차례일때 k보다 번호가 큰 학생들 중에 k번 학생과 친구인 학생을 찾아서 짝을 지어줘야 한다.

(0,1) 이나 (1,0)이나 결국 같은 케이스이기 때문에 중복을 피하기 위해 오름차순대로 짝을 맺어주는 것이다.

 

 

 

코드 설명

  • int isPair[a][b] 배열 

a번 학생과 b번 학생이 서로 친구이면 isPair[a][b] = isPair[b][a] = true 이고,

서로 친구가 아니면 isPair[a][b] = isPair[b][a] = false 이다.

        for(int j=0;j<m;j++){
            int a,b;
            scanf("%d %d",&a,&b);
            isPair[a][b]=isPair[b][a]=1;
        }

 

 

  • int child[n] 배열 

k번 학생이 짝을 지었을 때, 친구과 짝을 이루었으면 child[k] = true, 그렇지 않으면 child[k] = false (0<= k < n)

오름차순이므로 k번 이후의 학생들(k<i<n) 중 k번 학생과 친구이면서(isPair[k][i]=true) 아직 짝이 되지 못한 학생(child[i]=false)을 찾아서 짝을 만들어준다.

    for(int i=k+1;i<n;i++){
        if(isPair[k][i] && !child[i]){
            child[i]=child[k]=1;
            makePair(isPair, child,k+1);
            child[i]=child[k]=0;
        }
    }

 

 

 

오름차순 번호 순대로 짝을 지어주다가 k번 학생 차례가 됐다.

그런데 k번 학생이 자기보다 앞의 번호를 가진 학생 누군가와 이미 짝이 되어있는 상태라면? 즉, child[k] = true라면?

이미 짝이 되어있으므로 또 짝을 찾아줄 필요가 없다. 따라서, 이때는 본인은 pass하고, 다음(k+1번) 학생이 짝을 찾도록 넘겨준다.

   if(child[k]){
        makePair(isPair, child,k+1);
        return;
    }

 

 

 

base case. 

탐색은 0번부터 n-1번까지 오름차순 번호대로 진행된다. 따라서 n-1번 학생 차례일때는 자기보다 높은 번호가 없으니까 더 이상 짝을 지어줄 수 없다.(결국 이 상황에서 n-1번 학생은 이미 다른 학생과 짝이 지어진 상태여야 한다는 걸 알수 있다.)

    if(k==n-1){
        for(int i=0;i<n;i++){
            if(!child[i]){
                return;
            }
        }
        count++;
        
        return;
    }

마지막 n-1번 학생까지 탐색했을때, 0~n-1번 중 한명이라도 child[k] = false (0<=k<n)가 존재하면 문제의 조건(항상 서로 친구인 학생들끼리만 짝이 되는 경우의 수)에 만족하지 못하므로 카운트를 하지 않는다.

반면, child 배열이 모두 true인 경우, 0~4번 학생 모두 친구인 학생과 짝이 된 것이므로 카운트를 해준다.

 

 

 

재귀함수를 통해 모든 탐색을 진행한 후, 최종적으로 count 변수에 남아있는 값이 항상 서로 친구인 학생끼리 짝이 되는 모든 경우의 수가 된다.

 

 

전체코드 : 

#include <stdio.h>
int count;
int C,n,m;
void makePair(int isPair[10][10], int child[10], int idx);
int main(int argc, const char * argv[]) {
    
    scanf("%d",&C);
    
    for(int i=0;i<C;i++){
        count=0;
        int isPair[10][10]={{0}};
        int child[10]={0};
        
        scanf("%d %d",&n,&m);
        
        for(int j=0;j<m;j++){
            int a,b;
            scanf("%d %d",&a,&b);
            isPair[a][b]=isPair[b][a]=1;
        }
        
        makePair(isPair,child,0);
        printf("%d\n",count);
    }
    
    return 0;
}
void makePair(int isPair[10][10], int child[10], int k){
    
    if(k==n-1){
        for(int i=0;i<n;i++){
            if(!child[i]){
                return;
            }
        }
        count++;
        
        return;
    }
    
    if(child[k]){
        makePair(isPair, child,k+1);
        return;
    }
    
    for(int i=k+1;i<n;i++){
        if(isPair[k][i] && !child[i]){
            child[i]=child[k]=1;
            makePair(isPair, child,k+1);
            child[i]=child[k]=0;
        }
    }
    
    return;
}

'알고스팟' 카테고리의 다른 글

[알고스팟] 게임판 덮기  (0) 2023.05.01