반응형

문제링크:https://www.acmicpc.net/problem/2580

 

2580번: 스도쿠

스도쿠는 18세기 스위스 수학자가 만든 '라틴 사각형'이랑 퍼즐에서 유래한 것으로 현재 많은 인기를 누리고 있다. 이 게임은 아래 그림과 같이 가로, 세로 각각 9개씩 총 81개의 작은 칸으로 이루

www.acmicpc.net

 

일반적인 방법으로 풀면은 시간초과입니다.

 

dfs를 사용하고 이미 확인한 값에 대해서는 탐색하지 않는 백트래킹 기법을 사용해야 하는 어려운 문제였습니다.

 

 

이문제에서의 핵심은

bool row[9][10] = { 0 };
bool col[9][10] = { 0 };
bool square[9][10] = { 0 };

 세가지 방문여부입니다. row는 해당 행에서 수를 탐색했는지 여부, col은 열에서 수를 탐색했는지 여부, square는 속하는 3x3에서 수를 탐색했는지 여부를 판단합니다.

 

int main() {

	ios_base::sync_with_stdio(0);
	cin.tie(0);

	for (int i = 0; i < 9; i++)
		for (int j = 0; j < 9; j++) {
			cin >> arr[i][j];



			if (arr[i][j] != 0)
			{
				row[i][arr[i][j]] = true;
				col[j][arr[i][j]] = true;
				square[(i / 3) * 3 + (j / 3)][arr[i][j]] = true;
			}


		}

	dfs(0);



}

위 처럼 수를 입력받으면 row, col, square에 방문 수를 저장합니다. 

row[i][j] 라면 i행에서 j값을 방문했는지 여부를 표시합니다 즉 row[1][9]= true 면은 1행에 9는 존재한다는 의미입니다.

col과 square 모두 같은 맥락입니다.

이때 스퀘어는 

위와 같은 구조로 진행됩니다. (출처: 얍문님 티스토리)  

 

그렇기 때문에 (y/3)*3 + x/3 을 통해서 해당 위치에 표시하는 것입니다.

 

 

 

정답코드입니다. cnt값을 올려주며 진행하게 됩니다. 81일때에는 모든 값들이 채워져 있는 것이기에 종료하게 됩니다.

이때 exit(0)를 이용해서 바로 프로세스를 종료해버리면 시간을 단축시킵니다. 천천히 이해해보세요.

#include <iostream>
#include <cstring>
#include <stdlib.h>
using namespace std;

int arr[9][9] = { 0 };
bool row[9][10] = { 0 };
bool col[9][10] = { 0 };
bool square[9][10] = { 0 };




void dfs(int cnt) {

	if (cnt == 81) {
		for (int i = 0; i < 9; i++) {
			for (int j = 0; j < 9; j++)
				cout << arr[i][j] << ' ';
			cout << endl;
		}
		exit(0);
	}
	int y = cnt / 9;
	int x = cnt % 9;

	if (arr[y][x] != 0)
		dfs(cnt + 1);
	else {
		
		for (int i = 1; i <= 9; i++) {
			if (row[y][i] == 0 && col[x][i] == 0 && square[(y / 3) * 3 + (x / 3)][i] == 0) {
				row[y][i] = 1;
				col[x][i] = 1;
				square[(y / 3) * 3 + (x / 3)][i] = 1;

				arr[y][x] = i;
				dfs(cnt + 1);
				arr[y][x] = 0;

				row[y][i] = 0;
				col[x][i] = 0;
				square[(y / 3) * 3 + (x / 3)][i] = 0;

			}

		}

	}


	return;
	
}


int main() {

	ios_base::sync_with_stdio(0);
	cin.tie(0);

	for (int i = 0; i < 9; i++)
		for (int j = 0; j < 9; j++) {
			cin >> arr[i][j];



			if (arr[i][j] != 0)
			{
				row[i][arr[i][j]] = true;
				col[j][arr[i][j]] = true;
				square[(i / 3) * 3 + (j / 3)][arr[i][j]] = true;
			}


		}

	dfs(0);



}

 

반응형

'알고리즘 > DFS' 카테고리의 다른 글

[백준] 2023-신기한 소수(C++)  (0) 2021.01.02
[백준] 14267-내리 칭찬(C++)  (0) 2021.01.01
[백준] 9663-N-Queen(C++)  (0) 2020.07.27
[백준] 2573-빙산(C++)  (0) 2020.06.09
[백준] 1987-알파벳(C++)  (0) 2020.06.09
반응형

문제링크:https://www.acmicpc.net/problem/13460

 

13460번: 구슬 탈출 2

첫 번째 줄에는 보드의 세로, 가로 크기를 의미하는 두 정수 N, M (3 ≤ N, M ≤ 10)이 주어진다. 다음 N개의 줄에 보드의 모양을 나타내는 길이 M의 문자열이 주어진다. 이 문자열은 '.', '#', 'O', 'R', 'B'

www.acmicpc.net

 

 

이 문제는 13459번 구슬 탈출과 동일한 문제입니다. 다만 이동 경로값을 출력해주어야 하기 때문에 기존에 bfs를 사용하는게 편하다는 점이 있습니다. 

 

 

1. bfs와 while문을 사용하여 행동을 구현한다.

    - 이동할 곳이 #이 아니고 현재있는 좌표가 O가 아니면 계속 이동하게끔 구현한다.

2.이동후 두좌표가 같을때를 확인해준다.

    - 경우는 2가지이다. 함께 O에 있을때, 한쪽 끝에 함께 몰려있을때  함께 O라면 실패이기 때문에 큐에 넣지않고 마무       리 한쪽 끝이라면 값을 비교해서 하나를 한칸뒤로 무른다. 

3. 매 반복마다 result값을 증가시킨다. (구슬 탈출2 에서 유효)

 

 

정답코드입니다.

 

#include <iostream>
#include <queue>
#include <math.h>
using namespace std;

int n = 0, m = 0;
char arr[11][11];
bool visited[11][11][11][11] = { 0, };
int result = 0;

int ry, rx, by, bx;
int y_ar[4] = { 0,0,1,-1 };
int x_ar[4] = { 1,-1,0,0 };


int bfs() {
	queue <pair<int, int>> red_que;
	queue <pair<int, int>> blue_que;
	red_que.push(make_pair(ry, rx));
	blue_que.push(make_pair(by, bx));
	visited[ry][rx][by][bx] = 1;
	

	while (!red_que.empty()) {
		int sized = red_que.size();



		while (sized--) {

			int red_cy = red_que.front().first;
			int red_cx = red_que.front().second;
			int blue_cy = blue_que.front().first;
			int blue_cx = blue_que.front().second;


			red_que.pop(), blue_que.pop();

			if (arr[red_cy][red_cx] == 'O')
				return result;

			for (int i = 0; i < 4; i++) {
				int red_ny = red_cy;
				int red_nx = red_cx;
				int blue_ny = blue_cy;
				int blue_nx = blue_cx;

				while (arr[red_ny + y_ar[i]][red_nx + x_ar[i]] != '#' && arr[red_ny][red_nx] != 'O') {
					red_ny += y_ar[i];
					red_nx += x_ar[i];

				}
				while (arr[blue_ny + y_ar[i]][blue_nx + x_ar[i]] != '#' && arr[blue_ny][blue_nx] != 'O') {
					blue_ny += y_ar[i];
					blue_nx += x_ar[i];
				}

				if (red_ny == blue_ny && red_nx == blue_nx) {

					if (arr[red_ny][red_nx] == 'O') continue; // 할 필요가 없지

					if ((abs(red_ny - red_cy) + abs(red_nx - red_cx)) > (abs(blue_ny - blue_cy) + abs(blue_nx - blue_cx)))
						red_ny -= y_ar[i], red_nx -= x_ar[i];
					else
						blue_ny -= y_ar[i], blue_nx -= x_ar[i];
				}

				if (visited[red_ny][red_nx][blue_ny][blue_nx]) continue;

				red_que.push(make_pair(red_ny, red_nx));
				blue_que.push(make_pair(blue_ny, blue_nx));
				visited[red_ny][red_nx][blue_ny][blue_nx] = 1;

			}

		}

		if (result == 10)
			return -1;
		result++;

	}

	return -1;

}


int main() {

	ios_base::sync_with_stdio(0);
	cin.tie(0);

	cin >> n >> m;

	for (int i = 0; i < n; i++)
		for (int j = 0; j < m; j++) {
			cin >> arr[i][j];
			if (arr[i][j] == 'R')
				ry = i, rx = j, arr[i][j] = '.';
			else if (arr[i][j] == 'B')
				by = i, bx = j, arr[i][j] = '.';
		}

	cout << bfs() << endl;

	return 0;
}
반응형

'알고리즘 > 시뮬레이션' 카테고리의 다른 글

[백준] 8911-거북이(C++)  (0) 2021.01.10
[백준] 19236-청소년 상어(C++)  (0) 2020.09.04
[백준] 13459-구슬 탈출(C++)  (2) 2020.08.17
[백준] 16234-인구 이동(C++)  (0) 2020.08.12
[백준] 16236-아기 상어(C++)  (0) 2020.06.14
반응형

문제링크: https://www.acmicpc.net/problem/13459

 

13459번: 구슬 탈출

첫 번째 줄에는 보드의 세로, 가로 크기를 의미하는 두 정수 N, M (3 ≤ N, M ≤ 10)이 주어진다. 다음 N개의 줄에 보드의 모양을 나타내는 길이 M의 문자열이 주어진다. 이 문자열은 '.', '#', 'O', 'R', 'B'

www.acmicpc.net

 

까다로운 문제였습니다. 10번까지 검증하기 때문에 dfs가 아니라 bfs로 구현해야 했습니다.

 

1. bfs와 while문을 사용하여 행동을 구현한다. 

    - 이동할 곳이 #이 아니고 현재있는 좌표가 O가 아니면 계속 이동하게끔 구현한다.

2.이동후 두좌표가 같을때를 확인해준다.

    - 경우는 2가지이다. 함께 O에 있을때, 한쪽 끝에 함께 몰려있을때  함께 O라면 실패이기 때문에 큐에 넣지않고 마무       리 한쪽 끝이라면 값을 비교해서 하나를 한칸뒤로 무른다. 

3. 매 반복마다 result값을 증가시킨다. (구슬 탈출2 에서 유효)

 

 

정답코드입니다.

#include <iostream>
#include <queue>
#include <cmath>
using namespace std;

int n = 0, m = 0;
char arr[12][12];

int r_y, r_x;
int b_y, b_x;
int result = 0;

int y_ar[4] = { 0,0,1,-1 };
int x_ar[4] = { 1, -1, 0, 0 };
bool visited[12][12][12][12] = { 0, };

int bfs() {

	queue <pair <int, int>> b_que;
	queue <pair <int, int>> r_que;
	b_que.push(make_pair(b_y, b_x));
	r_que.push(make_pair(r_y, r_x));

	result = 0; // 0으로 초기화
	while (!b_que.empty()) {
		int sized = b_que.size();

		while (sized--) {
			int red_y = r_que.front().first;
			int red_x = r_que.front().second;
			int blue_y = b_que.front().first;
			int blue_x = b_que.front().second;
			r_que.pop(), b_que.pop();


			if (arr[red_y][red_x] == 'O') // O에 있을때
				return result;
			
			for (int i = 0; i < 4; i++) {
				int nextred_y = red_y;
				int nextred_x = red_x;
				int nextblue_y = blue_y;
				int nextblue_x = blue_x;

				while (arr[nextred_y + y_ar[i]][nextred_x + x_ar[i]] != '#' && arr[nextred_y][nextred_x] != 'O') {
					nextred_y += y_ar[i];
					nextred_x += x_ar[i];
				}
				while (arr[nextblue_y + y_ar[i]][nextblue_x + x_ar[i]] != '#' && arr[nextblue_y][nextblue_x] != 'O') {
					nextblue_y += y_ar[i];
					nextblue_x += x_ar[i];
				}
				if (nextred_y == nextblue_y && nextred_x == nextblue_x) {
					if (arr[nextred_y][nextred_x] == 'O') continue; // 이 경로는 가면 안되는 경로라서 continue로 넘겨줌 	

					// 더 많이 이동한쪽이 진짜 자기 위치  
					if ((abs(nextred_y - red_y) + abs(nextred_x - red_x)) > (abs(nextblue_y - blue_y) + abs(nextblue_x - blue_x)))
						nextred_y -= y_ar[i], nextred_x -= x_ar[i];
					else
						nextblue_y -= y_ar[i], nextblue_x -= x_ar[i];
						
				}

				if (visited[nextred_y][nextred_x][nextblue_y][nextblue_x]) continue; //기존에 방문했다면 
				r_que.push(make_pair(nextred_y,nextred_x));
				b_que.push(make_pair(nextblue_y,nextblue_x));
				visited[nextred_y][nextred_x][nextblue_y][nextblue_x] = 1;

			}


		}

		if (result == 10) return -1; 
		result++;
	}

	return -1;


}

int main() {

	ios_base::sync_with_stdio(0); 
	cin.tie(0);



	cin >> n >> m;

	for (int i = 0; i < n; i++)
		for (int j = 0; j < m; j++) {
			cin >> arr[i][j];
			if (arr[i][j] == 'B')
				b_y = i, b_x = j, arr[i][j] = '.';
			else if (arr[i][j] == 'R')
				r_y = i, r_x = j, arr[i][j] = '.';
		}


	if (bfs() == -1)
		cout << 0 << endl;
	else
		cout << 1 << endl;


	
	return 0;
}

스스로 부족한 것을 많이 느꼈습니다. 구슬탈출2를 풀어보면서 더욱 연습할 계획입니다. 

 

 

아래는 dfs를 통해 구현한 코드입니다.

#include <iostream>
#include <string>
#include <cmath>
using namespace std;

int n, m;
string arr[10];
bool result = 0;
int y_ar[4] = { 0,1,0,-1 };
int x_ar[4] = { -1,0,1,0 };

void dfs(int cnt, int ry, int rx, int by, int bx) {
	if (cnt == 10)
		return;
	if (result)
		return;

	for (int i = 0; i < 4; i++) {

		int nry = ry, nrx = rx;
		int nby = by, nbx = bx;
		bool blue = false, red = false;
		while (1) {

			if (arr[nry + y_ar[i]][nrx + x_ar[i]] == '.') {
				nry += y_ar[i];
				nrx += x_ar[i];
			}
			else if (arr[nry + y_ar[i]][nrx + x_ar[i]] == 'O') {
				nry += y_ar[i];
				nrx += x_ar[i];
				red = true;
				break;
			}
			else if (arr[nry + y_ar[i]][nrx + x_ar[i]] == '#') {
				break;
			}
		}

		while (1) {
			if (arr[nby + y_ar[i]][nbx + x_ar[i]] == '.') {
				nby += y_ar[i];
				nbx += x_ar[i];
			}
			else if (arr[nby + y_ar[i]][nbx + x_ar[i]] == 'O') {
				nby += y_ar[i];
				nbx += x_ar[i];
				blue = true;
				break;
			}
			else if (arr[nby + y_ar[i]][nbx + x_ar[i]] == '#') {
				break;
			}
		}

		if (blue == true)
			continue;
		if (red == true) {
			result = true;
			return;
		}

		if (nrx == nbx && nry == nby) {			//포개진 경우
			if (i == 0) {
				if (rx > bx) 	nrx += 1;	//빨간공이 밑에 있었던 경우
				else			nbx += 1;
			}
			else if (i == 1) {
				if (ry > by)	nby -= 1;		//파란공이 더 왼쪽에서 시작한 경우
				else			nry -= 1;
			}
			else if (i == 2) {
				if (rx > bx)		nbx -= 1;		//파란공이 더 위에서 시작
				else				nrx -= 1;
			}
			else if (i == 3) {
				if (ry > by)		nry += 1;		//빨간공이 더 오른쪽에서 시작
				else				nby += 1;
			}
		}

		dfs(cnt + 1, nry, nrx, nby, nbx);




	}

}
int main() {
	ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	cin >> n >> m;

	int ry, rx, by, bx;
	for (int i = 0; i < n; i++) {
		cin >> arr[i];
		for (int j = 0; j < m; j++) {
			if (arr[i][j] == 'R') {
				ry = i, rx = j;
				arr[i][j] = '.';
			}
			else if(arr[i][j] == 'B') {
				by = i, bx = j;
				arr[i][j] = '.';
			}
		}
	}

	dfs(0, ry, rx, by, bx);
	cout << result << endl;

	return 0;
}
반응형

'알고리즘 > 시뮬레이션' 카테고리의 다른 글

[백준] 19236-청소년 상어(C++)  (0) 2020.09.04
[백준] 13460-구슬 탈출2(C++)  (0) 2020.08.17
[백준] 16234-인구 이동(C++)  (0) 2020.08.12
[백준] 16236-아기 상어(C++)  (0) 2020.06.14
[백준] 11559-Puyo Puyo(C++)  (0) 2020.05.03
반응형

문제링크:https://www.acmicpc.net/problem/15684

 

15684번: 사다리 조작

사다리 게임은 N개의 세로선과 M개의 가로선으로 이루어져 있다. 인접한 세로선 사이에는 가로선을 놓을 수 있는데, 각각의 세로선마다 가로선을 놓을 수 있는 위치의 개수는 H이고, 모든 세로선

www.acmicpc.net

 

전형적인 브루트포스 문제입니다.

 만약, 정답이 3보다 큰 값이면 -1을 출력한다. 

이라는 조건이 있기 때문에 모든 경우의 수를 대입해서 결과를 유추할 수 있기 때문입니다.

 

저는 크게 두가지 기능으로 분류했습니다.

 

1. 경로를 선택하는 함수 SELECTED 

2. 해당 사다리가 올바르게 i번 세로선의 결과가 i번이 나오는지 확인하는 함수 JUDMENT

 

2번 함수 같은 경우에는 쉽게 구현이 가능합니다.

bool judment() {


	for (int i = 1; i <= n; i++) { //세로 

		int ii = i; //열

		for (int j = 1; j <= h; j++) {
			if (arr[j][ii] == 1)
				ii++;
			else if (arr[j][ii - 1] == 1) {
				ii--;
			}
		}

		if (ii != i)
			return false;
	}

	return true;
}

1번 함수같은 경우에는 조금 해맸는데, DFS를 사용해서 구현하였습니다.

 

void selected(int y, int cnt) {
	if (flag == true)
		return;

	if (cnt == leadercnt) {
		flag = judment();

		return;
	}

	for (int i = y; i <= h; i++) {
		for (int j = 1; j < n; j++) {
			if (arr[i][j] == 0 && arr[i][j - 1] == 0 && arr[i][j + 1] == 0)
			{

				arr[i][j] = 1;
				selected(i, cnt + 1);
				arr[i][j] = 0;
			}

		}
	}

	return;
}

 

FLAG값이 참이거나 원하는 CNT값과 같거나 큰 경우에는 더 진행할 필요가 없기때문에 RETURN;을 통해서 함수를 종료하였습니다. 그리고 매개변수 Y을 사용하여서 기존에 검사했던 좌표들을 중복으로 검사하지 않게끔 구현하였습니다. 

 

 

 

정답코드입니다.

/*
1. 선택하는 함수  selected
경로를 선택, visited에 쓰고 다시 지우고 판단함수 호출
2. 판단하는 함수  judment
반복문을 돌며 올바르게 동작하면 cnt값을 전달하게 끔
*/
#include <iostream>
using namespace std;

int n = 0, m = 0, h = 0;
bool arr[32][12] = { 0 };
int cnt = 0;
int leadercnt;


bool flag;

bool judment() {


	for (int i = 1; i <= n; i++) { //세로 

		int ii = i; //열

		for (int j = 1; j <= h; j++) {
			if (arr[j][ii] == 1)
				ii++;
			else if (arr[j][ii - 1] == 1) {
				ii--;
			}
		}

		if (ii != i)
			return false;
	}

	return true;
}


void selected(int y, int cnt) {
	if (flag == true)
		return;

	if (cnt == leadercnt) {
		flag = judment();

		return;
	}

	for (int i = y; i <= h; i++) {
		for (int j = 1; j < n; j++) {
			if (arr[i][j] == 0 && arr[i][j - 1] == 0 && arr[i][j + 1] == 0)
			{

				arr[i][j] = 1;
				selected(i, cnt + 1);
				arr[i][j] = 0;
			}

		}
	}

	return;
}




int main() {
	

	int a = 0, b = 0;

	cin >> n >> m >> h;
	for (int i = 0; i < m; i++) {
		cin >> a >> b;
		arr[a][b] = 1;
	}

	for (int i = 0; i <= 3; i++) {
		flag = false;
		leadercnt = i;
		selected(1, 0);

		if (flag == true) {
			cout << i << "\n";
			return 0;
		}
	}

	cout << -1 << "\n";
	return 0;

}
반응형
반응형

문제링크:https://www.acmicpc.net/problem/16234

 

16234번: 인구 이동

N×N크기의 땅이 있고, 땅은 1×1개의 칸으로 나누어져 있다. 각각의 땅에는 나라가 하나씩 존재하며, r행 c열에 있는 나라에는 A[r][c]명이 살고 있다. 인접한 나라 사이에는 국경선이 존재한다. 모��

www.acmicpc.net

 

시뮬레이션 문제입니다.

아래 조건들을 만족시키며 진행해야 합니다. 

 

/*
국경선을 공유하는 두 나라의 인구 차이가 L명 이상, R명 이하라면, 두 나라가 공유하는 국경선을 오늘 하루동안 연다.
위의 조건에 의해 열어야하는 국경선이 모두 열렸다면, 인구 이동을 시작한다.
국경선이 열려있어 인접한 칸만을 이용해 이동할 수 있으면, 그 나라를 오늘 하루 동안은 연합이라고 한다.
연합을 이루고 있는 각 칸의 인구수는 (연합의 인구수) / (연합을 이루고 있는 칸의 개수)가 된다. 편의상 소수점은 버린다.
연합을 해체하고, 모든 국경선을 닫는다.
*/

 

알고리즘 입니다.

  • 반복문을 통해서 각점들에서 dfs(혹은 bfs)를 통해서 인구이동이 가능한지 확인   
    - visited 사용(방문여부), sum(배열값 합), cnt 사용(배열 개수), vetor(방문 배열 좌표)
  • dfs(혹은 bfs)후에 변경된 값들을 arr에 저장, 이때 cnt는 2보다 크거나 같아야한다.  bool값도 변경한다.
  • bool값을 확인하고 반복문을 break할지 카운트값(result)을 올릴지 판단한다.

 

정답코드입니다.

 

#include <iostream>
#include <vector>
#include <cstring>
#include <math.h>
using namespace std;

int arr[51][51] = { 0 };
bool visited[51][51];

int n = 0, l = 0, r = 0;
int result = 0; 
int cnt, sum;
vector <pair <int, int>> vec;

//dfs 방향
int y_ar[4] = { 1,-1,0,0 };
int x_ar[4] = { 0,0,1,-1 };

void dfs(int yy, int xx) {

	for (int i = 0; i < 4; i++) {
		int y = yy + y_ar[i];
		int x = xx + x_ar[i];

		if (!visited[y][x]) {
			if (y >= 0 && y < n&&x >= 0 && x < n) {
				if (abs(arr[yy][xx] - arr[y][x]) >= l && abs(arr[yy][xx] - arr[y][x]) <= r) {
					visited[y][x] = 1;
					cnt++;
					sum += arr[y][x];
					vec.push_back(make_pair(y, x));
					dfs(y, x);
				}
			}
		}
	}
}


int main() {
	cin >> n >> l >> r;
	for (int i = 0; i < n; i++)
		for (int j = 0; j < n; j++)
			cin >> arr[i][j];

	while (1) {
		bool jud = false;
		memset(visited, 0, sizeof(visited));

		for (int i = 0; i < n; i++) {
			for (int j = 0; j < n; j++) {
				if (!visited[i][j]) {

					vec.clear();
					cnt = 1;
					sum = arr[i][j];
					visited[i][j] = 1;

					vec.push_back(make_pair(i,j));
					dfs(i, j);
					
					if (cnt >= 2) {
						jud = true;
						int aver_val = sum / cnt;
						for (int k = 0; k < vec.size(); k++) 
							arr[vec.at(k).first][vec.at(k).second] = aver_val;
						
					}

				}
			}
		}


		if (jud == false)
			break;
		else
			result++;


	}
	cout << result << endl;
}

 

반응형

'알고리즘 > 시뮬레이션' 카테고리의 다른 글

[백준] 13460-구슬 탈출2(C++)  (0) 2020.08.17
[백준] 13459-구슬 탈출(C++)  (2) 2020.08.17
[백준] 16236-아기 상어(C++)  (0) 2020.06.14
[백준] 11559-Puyo Puyo(C++)  (0) 2020.05.03
[백준] 14891-톱니바퀴(C++)  (0) 2020.04.28
반응형

문제링크: https://www.acmicpc.net/problem/9019

 

9019번: DSLR

문제 네 개의 명령어 D, S, L, R 을 이용하는 간단한 계산기가 있다. 이 계산기에는 레지스터가 하나 있는데, 이 레지스터에는 0 이상 10,000 미만의 십진수를 저장할 수 있다. 각 명령어는 이 레지스�

www.acmicpc.net

 

BFS를 사용하여 해결하는 문제였습니다. 

수의 범위가 0 이상 10,000 미만의 십진수이기 때문에 visited 배열을 만들어서 방문 했던 값을 표시하면서 시간을 확보 했습니다. queue를 pair로 사용해서 int, string 함께 저장하여 해결하였습니다. 

 

string을 쓰지않고 char형 만으로 구현하는게 베스트인 문제입니다! (사실 string을 사용하면 시간초과가 나게끔 유도한 느낌의 문제였습니다.. ㅠㅠ) 

 

#include <iostream>
#include <queue>
#include <string>
#include <cstring>
using namespace std;

int t = 0;
int a = 0, b = 0;
bool visited[10000];
int main() {
	ios_base::sync_with_stdio(0);
	cin.tie(0);

	cin >> t;

	string result;

	while (t--) {
		memset(visited, 0, sizeof(visited));

		result = "";

		cin >> a >> b;
		queue <pair<int, string>> que;
		// 0 -> D 1 -> S 2 -> L 3 -> R
		que.push(make_pair(a, ""));
		visited[a] = 1;
		string word;
		while (!que.empty()) {

			int num = que.front().first;
			word = que.front().second;
			que.pop();
			
			if (num == b) {
				result = word;
				break;
			}

			int verifed_num = (num * 2) % 10000;
			if(!visited[verifed_num])
				que.push(make_pair(verifed_num, word + "D")), visited[verifed_num] = 1;
			
			if (num == 0 && !visited[9999]) que.push(make_pair(9999, word + "S")), visited[9999] = 1;
			else if(!visited[num - 1])que.push(make_pair(num - 1, word + "S")), visited[num - 1] = 1;
			
			verifed_num = (num % 1000) * 10 + (num / 1000);
			if (!visited[verifed_num])
				que.push(make_pair(verifed_num, word + "L")), visited[verifed_num] = 1;
			verifed_num = (num / 10) + (num % 10) * 1000;
			if (!visited[verifed_num])
				que.push(make_pair(verifed_num, word + "R")), visited[verifed_num] = 1;

		}

		cout << result << "\n";
	}

}
반응형

'알고리즘 > BFS' 카테고리의 다른 글

[백준] 2606- 바이러스(C++)  (0) 2021.02.06
[백준] 1261-알고스팟(C++)  (0) 2020.08.25
[백준] 6593-상범 빌딩(C++)  (0) 2020.07.03
[백준] 4179-불!(C++)  (0) 2020.05.06
[백준] 5427-불(C++)  (0) 2020.05.06
반응형

문제링크:https://www.acmicpc.net/problem/1916

 

1916번: 최소비용 구하기

첫째 줄에 도시의 개수 N(1 ≤ N ≤ 1,000)이 주어지고 둘째 줄에는 버스의 개수 M(1 ≤ M ≤ 100,000)이 주어진다. 그리고 셋째 줄부터 M+2줄까지 다음과 같은 버스의 정보가 주어진다. 먼저 처음에는 그

www.acmicpc.net

 

1753번 문제와 똑같습니다. 한 정점에서의 최단경로를 구하기 위해서 다익스트라를 구현해야 합니다.  

다익스트라를 구현할때 우선순위 큐를 사용해야 합니다. 

min-heap을 이용해서 가장 작은 경로값 부터 적용해주며 진행하여야 컴팩트하게 구현할 수 있습니다.(일반 큐를 사용하면 틀립니다.)

 

 

정답코드입니다.

 

#include <iostream>
#include <queue>
#include <vector>
using namespace std;


int a = 0, b = 0; // 출발지, 도착지
int n = 0; // 도시의 개수
int m = 0; // 버스의 개수

vector <int> result;
vector <pair<int, int>> m_arr[1001];

void soultion(int start_index) {

	for (int i = 0; i <= n; i++)
		result.push_back(1000000000); // 최대 값으로 초기화

	priority_queue <pair <int, int >> que; //우선 순위 큐 생성
	que.push(make_pair(0,start_index));

	while (que.empty() == 0) {
		int cost = - que.top().first;
		int destination = que.top().second;
		que.pop();

		if (result[destination] < cost) continue; // 기존 경로가 더 가까우면 continue

		for (int i = 0; i < m_arr[destination].size(); i++) {
			int adjacent_cost =  m_arr[destination][i].second ;
			int adjacent_des = m_arr[destination][i].first;

			if (result[adjacent_des] > adjacent_cost + cost ) {
				result[adjacent_des] = adjacent_cost;
				que.push(make_pair(-result[adjacent_des], adjacent_des));
			}
		}

	}

}

int main(){
	cin >> n;
	cin >> m;
	int u, l, k;
	for (int i = 0; i < m; i++) {
		cin >> u >> l >> k;
		m_arr[u].push_back(make_pair(l, k)); // 
	}
	cin >> a >> b;

	soultion(a);

	cout << result[b] << endl;

	return 0;
}

https://gusdnr69.tistory.com/134?category=799066

 

[백준] 1753-최단경로

다익스트라 알고리즘을 이용해서 해결해야 하는 문제입니다. 왜? 그냥 que를 이용해서 구현하면 안되나 생각했습니다. 결과는 인접하는 정점으로 이동할때는 최소경로값으로 먼저 이동하면서 ��

gusdnr69.tistory.com

위 문제도 참고하세요. 

반응형
반응형

문제링크:https://www.acmicpc.net/problem/5624

 

5624번: 좋은 수

문제 정수 N개로 이루어진 수열 A가 있다. 이때, i번째 수가 그 앞에 있는 수 세 개의 합으로 나타낼 수 있을 때, 그 수를 좋다고 한다. (같은 위치에 있는 수를 여러 번 더해도 된다) 수열이 주어졌

www.acmicpc.net

구현문제입니다. 기존의 방식대로 구현하면 a + b + c = d 를 구하는 문제이기 때문에  O(n^3)이기 때문에 당연히 시간 초과 입니다. O(n^2)만에 해결해야 합니다. 

방법은 a + b = d - c 로 변환 하여 해결하는 것입니다.

 

i번째마다 이전 두개의 값 조합(a + b)으로 (d - c)를 만들 수 있는지 판별하고,

i까지의 값들의 두개의 값 조합(a + b)을 추가해주며 진행됩니다.

 

아래는 정답코드입니다. 구현이전 까지의 설계가 어렵고 구현자체는 쉬운 문제였습니다. 

#include <iostream>
using namespace std;

int n = 0, result = 0;
int arr[5000] = { 0 };
bool r[400000] = { 0 };

int main() {
	ios_base::sync_with_stdio(0);
	cin.tie(0);



	cin >> n;
	for (int i = 0; i < n; i++)
		cin >> arr[i];


	for (int i = 0; i < n; i++) {

		
	
		for (int j = 0; j < i; j++) { // a + b = d - c
			if (r[arr[i] - arr[j] + 200000]) {
				result++;
				//cout << arr[i] << endl;
				break;
			}
		}
		
		for (int j = 0; j <= i; j++) { // a + b check
			r[arr[i] + arr[j] + 200000] = 1;
		}
	}
	cout << result << endl;
}

 

반응형

'알고리즘 > 구현' 카테고리의 다른 글

[백준] 2636-치즈(C++)  (0) 2020.12.18
[백준] 14719-빗물(C++)  (0) 2020.12.15
[백준] 6593-상범 빌딩(C++)  (0) 2020.07.05
[백준] 5549-행성 탐사(C++)  (0) 2020.06.14
[백준] 1043-거짓말(C++)  (0) 2020.06.08

+ Recent posts