백준 2661번 (좋은수열, C++, Backtracking) [BAEKJOON]

좋은수열

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

시간 제한메모리 제한제출정답맞힌 사람정답 비율
1 초128 MB111695455418850.144%

문제

숫자 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 들 사이에는 빈칸을 두지 않는다.

예제 입력 1

7

예제 출력 1

1213121

출처

Olympiad > 한국정보올림피아드 > KOI 1997 > 중등부 1번

알고리즘 분류


1차 시도
BFS로 모든 경우를 다 만들어 놓고 시작하려니 N이 80 이 되는 순간 프로그램이 나락을 간다.

실패코드

#include <iostream>
#include <queue>
#include <cmath> 

using namespace std;

queue<pair<int,int>> myQueue;

int N;

void BFS(int N)
{
	myQueue.push({0, N});

	while (!myQueue.empty())
	{
		int x = myQueue.front().first;
		int n = myQueue.front().second;
		myQueue.pop();

		cout << n << " \n";
		if (n == 0)
		{
			//cout << x << " \n";
			continue;
		}
		for (int i = 1; i <= 3; i++)
		{
			if (i == 1)
			{
				myQueue.push({ x + 1 * pow(10, n - 1), n-1 });
			}
			else if (i == 2)
			{
				myQueue.push({ x + 2 * pow(10, n - 1), n - 1 });
			}
			else if (i == 3)
			{
				myQueue.push({ x + 3 * pow(10, n - 1), n - 1 });
			}
		}
	}

}


int main()
{
	cin >> N;
	BFS(N);
	return 0;
}

계산 중 깊이를 측정해보니 이건 노답 이라는 것을 깨달았다.

DFS로 변경
목표는 가장 낮은 숫자를 찾는 것 => 1부터 시작해서 탐색

#include <iostream>
#include <queue>
#include <cmath> 

using namespace std;

int N;

void DFS(int n, int value)
{
	if (n == 0)
	{
		cout << value << "\n";
		return;
	}

	for (int i = 1; i <= 3; i++)
	{
		if (i == 1)
		{
			DFS(n - 1, value + 1 * pow(10, n - 1));
		}
		else if (i == 2)
		{
			DFS(n - 1, value + 2 * pow(10, n - 1));
		}
		else if (i == 3)
		{
			DFS(n -1, value + 3 * pow(10, n - 1));
		}
	}
}

int main()
{
	cin >> N;
	DFS(N, 0);
	cout << "end";
	return 0;
}

N은 80까지 가능
80 자리…
string 으로 변환….

#include <iostream>
#include <string>

using namespace std;

int N;

void DFS(int n, string value)
{
	if (n == 0)
	{
		cout << value << "\n";
		return;
	}

	
	for (int i = 1; i <= 3; i++)
	{
		if (i == 1)
		{
			DFS(n - 1, value + '1');
		}
		else if (i == 2)
		{
			DFS(n - 1, value + '2');
		}
		else if (i == 3)
		{
			DFS(n - 1, value + '3');
		}
	}
}

int main()
{
	cin >> N;
	DFS(N, "");
	cout << "end";
	return 0;
}

조건에 부합하는 가장 처음 값이 정답

성공 코드(DFS)

#include <iostream>
#include <string>

using namespace std;

int N;
string number;

void DFS(char ch, int cnt)
{
	// 제일 먼저 조건에 부합하는 숫자가 답
	if (cnt - 1 == N) { 
		cout << number; 
		exit(0);
	}
	
	number += ch;
	
	for (int i = 1; i <= cnt/2; i++)
	{
		string a = number.substr(cnt - i, i);
		string b = number.substr(cnt - i * 2, i);

		if (a == b){ 
			// 나쁜 수열이면 지우고 리턴
			number.erase(cnt - 1);
			return;
		}
	}

	for (int i = 1; i <= 3; i++)
	{
		DFS(i + '0', cnt + 1);
	}

	// cnt - 1 자리가 성립하지 않을 경우
	number.erase(cnt - 1);
}

int main()
{
	cin >> N;
	for (int i = 1; i <= 3; i++)
	{
		// '0' 에서 i 만큼 더하면 i
		DFS(i + '0', 1);
	}

	return 0;
}

댓글 달기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

위로 스크롤