안녕하세요.

여행벌입니다.

오늘은 대표적인 백트래킹 문제 LOTTO 풀이를 해보겠습니다.


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

 

6603번: 로또

문제 독일 로또는 {1, 2, ..., 49}에서 수 6개를 고른다. 로또 번호를 선택하는데 사용되는 가장 유명한 전략은 49가지 수 중 k(k>6)개의 수를 골라 집합 S를 만든 다음 그 수만 가지고 번호를 선택하는 것이다. 예를 들어, k=8, S={1,2,3,5,8,13,21,34}인 경우 이 집합 S에서 수를 고를 수 있는 경우의 수는 총 28가지이다. ([1,2,3,5,8,13], [1,2,3,5,8,21], [1,2,3,5,8,34], [1,2

www.acmicpc.net

[알고리즘풀이]

1. 백트레킹기법을 이용하여 k개의 수를 고르면 출력을 반복해줍니다.

#include<cstdio>
#include<vector>

using namespace std;

int list[12];

void printPicked(vector<int>& picked) {
	for (int i = 0; i < 6; i++)
		printf("%d ", list[picked[i]]);
	printf("\n");
}

void pick(int ninput, vector<int>& picked, int toPick) {
	if (toPick == 0) {
		printPicked(picked);
		return;
	}
	int smallest = picked.empty() ? 0 : picked.back() + 1;
	for (int next = smallest; next < ninput; next++) {
		picked.push_back(next);
		pick(ninput, picked, toPick - 1);
		picked.pop_back();
	}
}

int main(void) {
	while(1){
		int ninput;
		scanf("%d", &ninput);

		if (ninput == 0) {
			return 0;
		}

		for (int i = 0; i < ninput; i++)
			scanf("%d", &list[i]);

		for (int i = 0; i <= ninput - 6; i++) {
			vector<int> picked;
			picked.push_back(i);
			pick(ninput, picked, 5);
			picked.pop_back();
		}
		printf("\n");
	}
}

열심히 공부하고 노력하고 있는 꿈 많은 예비 개발자입니다.

혼자서 공부한 내용을 정리하고 포스팅하다 보니 틀린 내용이 있을 수도 있습니다.

많은 조언과 가르침 주실 분은 댓글로 자유롭게 남겨주셔도 좋을 것 같습니다! 

감사합니다.

'Problem Solving > BOJ' 카테고리의 다른 글

[BOJ] 1436 - 영화감독 숌  (0) 2019.08.21
[BOJ] 2456 - 나는 학습회장이다.  (0) 2019.08.21
[BOJ] 2579 - 계단 오르기  (0) 2019.08.21
[BOJ] 2668 - 숫자고르기  (0) 2019.08.16
[BOJ] 14503 - 로봇청소기  (0) 2019.08.16

안녕하세요.

여행벌입니다.


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

 

9019번: DSLR

문제 네 개의 명령어 D, S, L, R 을 이용하는 간단한 계산기가 있다. 이 계산기에는 레지스터가 하나 있는데, 이 레지스터에는 0 이상 10,000 미만의 십진수를 저장할 수 있다. 각 명령어는 이 레지스터에 저장된 n을 다음과 같이 변환한다. n의 네 자릿수를 d1, d2, d3, d4라고 하자(즉 n = ((d1 × 10 + d2) × 10 + d3) × 10 + d4라고 하자) D: D 는 n을 두 배로 바꾼다. 결과 값이 9999 보다 큰 경

www.acmicpc.net

[알고리즘설계]

1. A에서 시작해서 명령어 D / S / L / R  을 한 숫자가 아직 방문하지 않은 숫자라면 queue에 담아 가며 B가 나올 때까지 BFS 탐색을 진행한다. 이때, int path[10000], char answer[10001] 을 이용해서 방문 경로를 저장한다.

2. B에서 다시 방문 경로를 역 탐색하며 출력해준다.

#include<iostream>
#include<queue>

using namespace std;

char DSLR[5] = "DSLR";
void BFS(int, int);

int main(void) {
	ios::sync_with_stdio(false);
	cin.tie(0);

	int t;
	cin >> t;
	for (int i = 0; i < t; i++) {
		int A, B;
		cin >> A >> B;
		BFS(A,B);
	}
}

void BFS(int A, int B) {
	bool check[10000] = {};
	int npath[10000] = {};
	char cpath[10001] = {};
	queue<int> q;
	q.push(A);
	check[A] = true;
	while (!q.empty()) {
		int x = q.front(); q.pop();
		if (x == B) {
			vector<char>answer;
			while (x != A) {
				answer.push_back(cpath[x]);
				x = npath[x];
			}
			int length = (int)answer.size();
			for (int i = 0; i < length; i++)
				cout << answer[length - 1 - i];
			cout << '\n';
			return;
		}
		int list[4] = { (2 * x) % 10000, x - 1, (x % 1000) * 10 + x / 1000, (x % 10) * 1000 + x / 10 };
		if (list[1] < 0)
			list[1] = 9999;
		for (int i = 0; i < 4; i++) {
			if (!check[list[i]]) { // 지금 가려는 곳이 방문한 곳이 아니라면
				q.push(list[i]);
				check[list[i]] = true;
				npath[list[i]] = x;
				cpath[list[i]] = DSLR[i];
			}
		}

	}
}

코드는 간단하지만 구현하는데 정말 고생한 문제입니다...!


열심히 공부하고 노력하고 있는 꿈 많은 예비 개발자입니다.

혼자서 공부한 내용을 정리하고 포스팅하다 보니 틀린 내용이 있을 수도 있습니다.

많은 조언과 가르침 주실 분은 댓글로 자유롭게 남겨주셔도 좋을 것 같습니다! 

감사합니다.

 

'Problem Solving > ICPC' 카테고리의 다른 글

[ACM-ICPC][BOJ] 8896 - Rock Paper Scissors  (0) 2019.09.04
[ACM-ICPC][BOJ] 10251 - Driving License  (0) 2019.08.27
[ACM-ICPC][BOJ] 3758 - KCPC  (0) 2019.08.09
[ACM-ICPC][BOJ] 7287 - Registration  (0) 2019.08.08
[ACM-ICPC][BOJ] 9011 - Order  (0) 2019.08.08

안녕하세요.

여행벌입니다.

오늘은 백준 사이트 2668번 '숫자고르기' 문제를 다뤄보겠습니다.

정보올림피아드 초등부 문제로 DFS 탐색을 이용해서 구현할 수 있었습니다.


[알고리즘설계]

1. 입력된 정수를 list에 담고 앞에서부터 다음과 같이 탐색을 진행한다.

- 아직 방문하지않은 점이라면 Cycle이 형성되거나 이미 탐색한 점이 나올때까지 탐색을 진행한다.

 -> Cycle이 형성되었다면, Cycle의 크기만큼 Count 해주고, Cycle에 속한 숫자들을 Answer_list에 담아준다.

( Cycle의 형성 유무는 탐색을 하며 지나왔던 숫자와 다음에 가야할 숫자를 비교하며 판단한다. )

 -> 이미 탐색한 점이 나왔다면, 기존에 탐색한 루트이므로 종료한다.

2. 모든 점에 대한 탐색이 끝났다면, Answer_list를 Sort 한 후 앞에서부터 출력해준다.

 

[예시]

Index [ 1 2 3 4 5 6 7 ]

Input [ 3 1 1 5 5 4 6 ]

1 -> 3 -> 1 (Cycle 형성, 1,3을 Answer_list에 담아준다.)

2 -> 1 ( 1은 이미 방문한 점이므로 탐색을 종료한다. )

3 ( 1에서 탐색을 진행할 때 이미 방문한 점이므로 탐색을 종료한다. )

4 -> 5 -> 5 (Cycle 형성, 5를 Answer_list에 담아준다.)

5 ( 4에서 탐색을 진행할 때 이미 방문한 점이므로 탐색을 종료한다. )

6 -> 4 ( 4는 이미 방문한 점이므로 탐색을 종료한다. )

7 -> 6 ( 6은 이미 방문한 점이므로 탐색을 종료한다.

 

#include<iostream>
#include<algorithm>
using namespace std;

int answer[100], nanswer = 0;
int list[101];
bool check[101];
int check_circle(int, int, int[]);
void circle(int);

int main(void) {
	ios::sync_with_stdio(false);
	cin.tie(0);
    
	int ninput;
	cin >> ninput;
	for (int i = 1; i <= ninput; i++)
		cin >> list[i];
        
	for (int i = 1; i <= ninput; i++) {
		if(check[i] == false) //방문하지않은점이라면 탐색 시작.
			circle(i);
	}
    
	cout << nanswer << '\n';
	sort(answer, answer + nanswer);
	for (int i = 0; i < nanswer; i++)
		cout << answer[i] << '\n';
}

int check_circle(int next, int count, int temp[]) {
	int i;
	for (i = count - 1; i >= 0; i--) {
		if (temp[i] == next) {
			return i;
		}
	}
	return -1;
}

void circle(int i) {
	int temp[100];
	int start = i;
	check[start] = true;
	int count = 0;
	temp[count++] = start;
	while (1) {
		int next = list[start];
		int ntemp = check_circle(next, count, temp);
		if (ntemp != -1) {
			for (int j = ntemp; j < count; j++) {
				answer[nanswer++] = temp[j];
			}
			return;
		}
        // 기존에 방문한 점이라면 종료.
		if (check[next] == true)
			return;
		start = next;
		check[start] = true;
		temp[count++] = start;
	}
}

초등부 문제라 입력은 작지만, 구현이 생각보다 까다로웠던 문제입니다. 

비슷한 문제로는 BOJ 9466번을 추천드립니다!


열심히 공부하고 노력하고 있는 꿈 많은 예비 개발자입니다.

혼자서 공부한 내용을 정리하고 포스팅하다 보니 틀린 내용이 있을 수도 있습니다.

많은 조언과 가르침 주실 분은 댓글로 자유롭게 남겨주셔도 좋을 것 같습니다! 

감사합니다.

'Problem Solving > BOJ' 카테고리의 다른 글

[BOJ] 1436 - 영화감독 숌  (0) 2019.08.21
[BOJ] 2456 - 나는 학습회장이다.  (0) 2019.08.21
[BOJ] 2579 - 계단 오르기  (0) 2019.08.21
[BOJ] 6603 - LOTTO  (0) 2019.08.21
[BOJ] 14503 - 로봇청소기  (0) 2019.08.16

안녕하세요.

여행벌입니다.

오늘은 백준사이트의 14503번 '로봇청소기' 문제 풀이를 해보겠습니다.


[문제해석]

한글 문제라 따로 다루지 않겠습니다.

 

[알고리즘설계]

1. 시작 점부터 반시계 방향으로 돌며 청소를 안 한 곳이 있으면 청소를 해나간다.

(청소를 하지 않은 곳은 0, 벽은 1, 청소를 한 곳은 2를 저장해나가며 청소를 진행한다.)

2. 모든 방향을 돌았는데, 갈 곳이 없다면 후진을 한다.

- 후진을 할 수 있으면 후진 후 다시 1번부터 진행.

- 후진을 할 수 없다면(뒤가 벽이라면) 종료한다.

#include<iostream>

using namespace std;

int map[50][50];
int dx[4] = { 0,-1,0,1 };
int dy[4] = { -1, 0, 1, 0 };

int main(void) {
	ios::sync_with_stdio(false);
	cin.tie(0);

	int row, column;
	cin >> row >> column;
	int x, y, dir;
	// dir 0 북 1 동 2 남 3 서
	cin >> x >> y >> dir;
	for (int i = 0; i < row; i++)
		for (int j = 0; j < column; j++)
			cin >> map[i][j];

	int count = 0;
	int flag = 1; // 조건을 만족하면 0으로 바꾸고 while을끝낸다.
	while (flag) {
		if (!map[x][y])
			count++;
		map[x][y] = 2;
		for (int i = 0; i < 5; i++) {
			if (i == 4) { // 4바퀴를 다 돌았는데도 for문이 안깨짐 -> 후진하거나 멈춰야됨.
				int next_x = x + dx[(dir + 3) % 4];
				int next_y = y + dy[(dir + 3) % 4];
				if (0 <= next_x && next_x < row && 0 <= next_y && next_y < column && map[next_x][next_y] != 1) {
					x = next_x;
					y = next_y;
				}
				else
					flag = 0;
                break;
			}
			int next_x = x + dx[dir];
			int next_y = y + dy[dir];
			dir = (dir + 3) % 4;
			if (0 <= next_x && next_x < row && 0 <= next_y && next_y < column && !map[next_x][next_y]) {
				x = next_x;
				y = next_y;
				break;
			}
		}
	}
	cout << count;
}

[중요코드]

int dx[4] = {0,-1,0,1};
int dy[4] = {-1,0,1,0};

// 뒤로 후진해야하는경우.
int next_x = x + dx[(dir + 3) % 4];
int next_y = y + dy[(dir + 3) % 4];

// 왼쪽으로 반시계방향으로 도는 경우
int next_x = x + dx[dir];
int next_y = y + dy[dir];
dir = (dir + 3) % 4;

0(북), 1(동), 2(남), 3(서) 를 의미하고 우리는 반시계 방향(왼쪽)으로 회전하면서 청소할 공간이 있는지 찾아볼 것이다.

또, 모든 방향에 청소할 공간이 없다면 뒤로 후진을 해야 한다.

따라서 dx, dy 배열을 다음과 같이 선언하고 next_x, next_y를 위와 같이 다루면 깔끔하게 탐색을 진행할 수 있다.


dx, dy 배열을 선언하고 next_x, next_y 변수를 다루는데 미숙해 생각보다 구현하는데 오래 걸렸다.

 

열심히 공부하고 노력하고 있는 꿈 많은 예비 개발자입니다.
혼자서 공부한 내용을 정리하고 포스팅하다 보니 틀린 내용이 있을 수도 있습니다.
많은 조언과 가르침 주실 분은 댓글로 자유롭게 남겨주셔도 좋을 것 같습니다! 
감사합니다.

 

'Problem Solving > BOJ' 카테고리의 다른 글

[BOJ] 1436 - 영화감독 숌  (0) 2019.08.21
[BOJ] 2456 - 나는 학습회장이다.  (0) 2019.08.21
[BOJ] 2579 - 계단 오르기  (0) 2019.08.21
[BOJ] 6603 - LOTTO  (0) 2019.08.21
[BOJ] 2668 - 숫자고르기  (0) 2019.08.16

+ Recent posts