본문으로 바로가기

[DFS] 2661번 좋은수열

category Algorithm/BOJ 문제풀이 2019. 1. 7. 14:01
2661_좋은수열

2661번 좋은수열

 

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


 

문제

숫자 1, 2, 3으로만 이루어지는 수열이 있다. 임의의 길이의 인접한 두 개의 부분 수열이 동일한 것이 있으면, 그 수열을 나쁜 수열이라고 부른다. 그렇지 않은 수열은 좋은 수열이다.

다음은 나쁜 수열의 예이다.

  • 33
  • 32121323
  • 123123213

다음은 좋은 수열의 예이다.

  • 2
  • 32
  • 32123
  • 1232123

길이가 N인 좋은 수열들을 N자리의 정수로 보아 그중 가장 작은 수를 나타내는 수열을 구하는 프로그램을 작성하라. 예를 들면, 1213121과 2123212는 모두 좋은 수열이지만 그 중에서 작은 수를 나타내는 수열 1213121이다.

 

입력

입력은 숫자 N하나로 이루어진다. N은 1 이상 80 이하이다.

 

출력

첫 번째 줄에 1, 2, 3으로만 이루어져 있는 길이가 N인 좋은 수열들 중에서 가장 작은 수를 나타내는 수열만 출력한다. 수열을 이루는 1, 2, 3들 사이에는 빈칸을 두지 않는다.

 

예제 입력

7

 

예제 출력

1213121

 

해결방법

DFS + 백트래킹으로 가장 먼저 나오는 답을 출력하는 문제이다

 

좋은수열은 같은 수열이 반복되지 않아야 한다

그리고 좋은수열 중 가장 작은 값을 찾아야한다

 

백트래킹을 위해 Vector 를 활용하였다

벡터에 1,2,3 중 하나의 값을 넣은 뒤, 만약 좋은수열의 조건에 맞다면 재귀를 통해 탐색을 진행한다

만약 좋은수열의 조건에 맞지 않다면 벡터에서 값을 뺀 뒤, 다음 값으로 넘어간다

for(int i=1; i<=3; i++){
    v.push_back(i);
    
    if(is_goodPermutation())
        dfs(cnt+1);
        
    v.pop_back();
}

 

좋은수열의 조건을 확인하는 함수이다

만약 수열이 1 2 1 3 이라면 3 1 , 12 13 을 비교해야한다

i : 비교할 수열의 자리수

j : i 자리수 만큼 반복하여 수열을 만듬

bool is_goodPermutation(){
    int len = (int) v.size();
    
    for(int i=1; i<=len/2; i++){
        string s1 = "";
        string s2 = "";
        
        for(int j=0; j<i; j++){
            s1 += to_string(v[len - (2*i) + j]);
            s2 += to_string(v[len - i + j]);
        }
        if(s1 == s2) return false;
    }
    return true;
}

 

 

소스코드

#include <iostream>
#include <stdio.h>
#include <math.h>
#include <cstring>
#include <queue>
#include <set>
#include <vector>
#include <algorithm>
#define MAX 80
#define INF 987654321
using namespace std;

int n;
vector<int> v;

// 좋은 수열인지 확인하는 함수
bool is_goodPermutation(){
    int len = (int) v.size();
    
    // i = 비교할 수열의 자리수
    // 만약 길이가 4라면 1자리, 2자리 수열을 비교해야함
    for(int i=1; i<=len/2; i++){
        string s1 = "";
        string s2 = "";
        
        // i 자리 길이의 수열을 만듬
        for(int j=0; j<i; j++){
            s1 += to_string(v[len - (2*i) + j]);
            s2 += to_string(v[len - i + j]);
        }
        
        // 만약 두개의 수열이 같다면 좋은 수열이 아님
        if(s1 == s2) return false;
    }
    return true;
}

void dfs(int cnt){
    // 좋은 수열의 조건을 가진 채로 cnt == n 이라면
    if(cnt == n){
        for(int i=0; i<v.size(); i++){
            cout << v[i];
        }
        cout << "\n";
        exit(0);
    }
    
    // 1,2,3 의 숫자를 넣어보고
    // 만약 좋은 수열의 조건에 만족한다면 DFS 진행
    for(int i=1; i<=3; i++){
        v.push_back(i);
        
        if(is_goodPermutation())
            dfs(cnt+1);
            
        v.pop_back();
    }
}

int main(int argc, const char * argv[]) {
    // cin,cout 속도향상
    ios_base::sync_with_stdio(false);
    cin.tie(NULL); cout.tie(NULL);
    
    cin >> n;
    
    dfs(0);
    return 0;
}

 

'Algorithm > BOJ 문제풀이' 카테고리의 다른 글

[DFS] 16197번 두 동전  (0) 2019.01.07
[DFS] 10597번 순열 장난  (0) 2019.01.07
[BFS] 2636번 치즈  (0) 2019.01.06
[Dijkstra] 2151번 거울 설치  (0) 2019.01.05
[BF] 2503번 숫자 야구  (0) 2019.01.05