본문 바로가기

PS(알고리즘 문제풀이) 관련 글/PS일지

2024-02-28

-분수의 합(1735, 백준)

두 분수를 입력받아 두 분수의 합을 기약분수의 형태로 나타내는 문제이다. 우선, 두분수를 통분시킨후, 만들어진 분수의 분자, 분모를 가지고 GCD를 돌리면 되는 간단한 문제이다.(기약분수 -> 서로소 = GCD 가 1인경우)

<소스코드>

더보기
#include <stdio.h>

int a, b;
int c, d;

int GCD(int x, int y)
{
	if (y == 0) return x;
	else return GCD(y, x % y);
}

int main()
{
	int i, j;
	scanf("%d %d", &a, &b);
	scanf("%d %d", &c, &d);
	int x = (a * d) + (c * b);
	int y = d * b;
	while (1)
	{
		int gc;
		if (x > y) gc = GCD(x, y);
		else gc = GCD(y, x);
		if (gc == 1) break;
		x /= gc;
		y /= gc;
	}
	printf("%d %d", x, y);
	return 0;
}

-소수&팰린드롬(1747, 백준)

N보다 크거나 같고, 소수인 팰린드롬(뒤집어도 같은수)를 구하는 문제이다. 에라토스테네스의 체 + 팰린드롬문제이다. 에라토스테네스의 체로 n보다큰 소수를 검사해가며 팰린드롬이라면 출력하면 된다.

<소스코드>

더보기
#include <stdio.h>
#include <vector>

using namespace std;

int prime[1100010];
vector <int> vec;
int n;

void IsPrime()
{
	int i, j;
	prime[2] = 1;
	for (i = 3; i <= 1100000; i++) {
		if (i % 2 == 0 || prime[i] == 1) continue;
		for (j = i * 2; j <= 1100000; j += i) {
			prime[j] = 1;
		}
	}
	if(n <= 2) vec.push_back(2);
	for (i = 3; i <= 1100000; i++) if (i >= n && i % 2 != 0 && prime[i] == 0) vec.push_back(i);
	return;
}

int main()
{
	int i, j;
	scanf("%d", &n);
	IsPrime();
	for (i = 0; i < vec.size(); i++) {
		vector <int> pel;
		int x = vec[i];
		while (x >= 1) {
			pel.push_back(x % 10);
			x /= 10;
		}
		int siz = pel.size();
		int ch = 0;
		for (j = 0; j < siz / 2; j++) {
			if (pel[j] != pel[siz - j - 1]) ch = 1;
		}
		if (ch == 0) {
			printf("%d", vec[i]);
			break;
		}
	}
	return 0;
}

-벽 부수고 이동하기 2(14442, 백준)

3차원 배열을 이용해 방문처리를 해주면된다. dis[i][j][k] => 1, 1에서 i, j까지 k번 벽을 부수며 갔을때 걸리는 최소 경로.

<소스코드>

더보기
#include <stdio.h>
#include <queue>
#include <algorithm>

using namespace std;

struct dat {
	int x, y, br;
};

int n, m, k;
int map[1010][1010];
int dis[1010][1010][15];
int dx[5] = { 0, 0, 1, -1 };
int dy[5] = { 1, -1, 0, 0 };

void BFS(int x, int y)
{
	int i;
	queue <dat> q;
	q.push({ x, y, 0 });
	dis[x][y][0] = 0;
	while (!q.empty()) {
		int n_x = q.front().x, n_y = q.front().y, n_br = q.front().br;
		q.pop();
		for (i = 0; i < 4; i++) {
			int nx = n_x + dx[i], ny = n_y + dy[i];
			if (nx < 0 || ny < 0 || nx >= n || ny >= m) continue;
			if (map[nx][ny] == 0 && dis[nx][ny][n_br] > dis[n_x][n_y][n_br] + 1) {
				dis[nx][ny][n_br] = dis[n_x][n_y][n_br] + 1;
				q.push({ nx, ny, n_br });
			}
			if (n_br + 1 <= k) {
				if (map[nx][ny] == 1 && dis[nx][ny][n_br + 1] > dis[n_x][n_y][n_br] + 1) {
					dis[nx][ny][n_br + 1] = dis[n_x][n_y][n_br] + 1;
					q.push({ nx, ny, n_br + 1 });
				}
			}
		}
	}
}

int main()
{
	int i, j;
	scanf("%d %d %d", &n, &m, &k);
	for (i = 0; i < n; i++) {
		for (j = 0; j < m; j++) {
			scanf("%1d", &map[i][j]);
			for (int l = 0; l <= k; l++) dis[i][j][l] = 2e9;
		}
	}
	BFS(0, 0);
	int ans = 2e9;
	for (i = 0; i <= k; i++) ans = min(ans, dis[n - 1][m - 1][i]);
	if (ans == 2e9) printf("-1");
	else printf("%d", ans + 1);
	return 0;
}

-말이 되고픈 원숭이(1600, 백준)

마찬가지로 3차원 배열을 이용해 방문처리를 해주면된다. dis[i][j][k] => 1, 1에서 i, j까지 k번 말처럼 이동하여 갔을때 걸리는 최소 경로.

더보기
#include <stdio.h>
#include <algorithm>
#include <queue>

using namespace std;

int n, m, k;
int dis[210][210][35];
int map[210][210];
int dx[5] = { 0, 0, 1, -1 };
int dy[5] = { 1, -1, 0, 0 };
int kx[10] = { 2, 2, 1, 1, -1 ,-1, -2, -2 };
int ky[10] = { 1, -1, 2, -2, 2, -2, 1, -1 };

struct dat {
	int x, y, jump;
};

void BFS(int x, int y)
{
	int i;
	queue<dat> q;
	q.push({ x, y, 0 });
	dis[x][y][0] = 0;
	while (!q.empty()) {
		int n_x = q.front().x, n_y = q.front().y, n_jump = q.front().jump;
		q.pop();
		for (i = 0; i < 4; i++) {
			int nx = n_x + dx[i], ny = n_y + dy[i];
			if (nx < 0 || ny < 0 || nx >= n || ny >= m) continue;
			if (map[nx][ny] == 0 && dis[nx][ny][n_jump] > dis[n_x][n_y][n_jump] + 1) {
				dis[nx][ny][n_jump] = dis[n_x][n_y][n_jump] + 1;
				q.push({ nx, ny, n_jump });
			}
		}
		if (n_jump + 1 <= k) {
			for (i = 0; i < 8; i++) {
				int nx = n_x + kx[i], ny = n_y + ky[i];
				if (nx < 0 || ny < 0 || nx >= n || ny >= m) continue;
				if (map[nx][ny] == 0 && dis[nx][ny][n_jump + 1] > dis[n_x][n_y][n_jump] + 1) {
					dis[nx][ny][n_jump + 1] = dis[n_x][n_y][n_jump] + 1;
					q.push({ nx, ny, n_jump + 1 });
				}
			}
		}
	}
}

int main()
{
	int i, j;
	scanf("%d %d %d", &k, &m, &n);
	for (i = 0; i < n; i++) {
		for (j = 0; j < m; j++) {
			scanf("%d", &map[i][j]);
			for (int l = 0; l <= k; l++) dis[i][j][l] = 2e9;
		}
	}
	BFS(0, 0);
	int ans = 2e9;
	for (i = 0; i <= k; i++) ans = min(ans, dis[n - 1][m - 1][i]);
	if (ans == 2e9) printf("-1");
	else printf("%d", ans);
	return 0;
}

-백조의 호수(3197, 백준)

  BFS 심화문제이다. 처음부터 빙판을 녹이며 탐색했다간 시간초과가 나오게됨으로, 다음과같은 두 조건을 찾은 뒤 탐색해 주어야한다.

1. 빙판을 녹일땐, 바로 전날 녹았던 빙판에서 시작하면된다.(queue에 담아서 처리)

2. 백조를 탐색할때 만난 빙판은 다음날 녹게됨으로, 미리 queue에 담아두었다가 다음날 처리하면 된다.

이렇게 BFS를 돌리면 O(C*R)안에 풀린다. 한참해맸던 문제이다.

더보기
#include <stdio.h>
#include <queue>
#include <vector>

using namespace std;

int R, C;
char s[1510][1510];
int ch[1510][1510], ch2[1510][1510];
queue <pair<int, int>> q, q1, q2, q3;
int dx[5] = { 0, 0, 1, -1 };
int dy[5] = { 1, -1, 0, 0 };

int main()
{
	int i, j;
	scanf("%d %d", &R, &C);
	for (i = 0; i < R; i++) scanf("%s", s[i]);
	int sx, sy;
	for (i = 0; i < R; i++) {
		for (j = 0; j < C; j++) {
			if (s[i][j] == 'L') sx = i, sy = j;
			if (s[i][j] != 'X') q.push({ i, j });
		}
	}
	int day = 0;
	q2.push({ sx, sy });
	ch2[sx][sy] = 1;
	while (1)
	{
		while (!q.empty()) {
			int n_x = q.front().first, n_y = q.front().second;
            ch[n_x][n_y] = 1;
			q.pop();
			for (i = 0; i < 4; i++) {
				int nx = n_x + dx[i], ny = n_y + dy[i];
				if (nx < 0 || ny < 0 || nx >= R || ny >= C) continue;
				if (ch[nx][ny] == 1) continue;
				if(s[nx][ny] == 'X') q1.push({nx, ny});
			    ch[nx][ny] = 1;
			}
		}
		while (!q1.empty()) {
			int nx = q1.front().first, ny = q1.front().second;
			q1.pop();
			s[nx][ny] = '.';
			q.push({ nx, ny });
		}
		day++;
		while (!q2.empty()) {
			int n_x = q2.front().first, n_y = q2.front().second;
			q2.pop();
			for (i = 0; i < 4; i++) {
				int nx = n_x + dx[i], ny = n_y + dy[i];
				if (nx < 0 || ny < 0 || nx >= R || ny >= C) continue;
				if (ch2[nx][ny] == 1) continue;
				ch2[nx][ny] = 1;
				if (s[nx][ny] == 'X') {
					q3.push({ nx, ny });
					continue;
				}
				if (s[nx][ny] == 'L') {
					printf("%d", day);
					return 0;
				}
				q2.push({ nx, ny });
			}
		}
		while (!q3.empty()) {
			q2.push(q3.front());
			q3.pop();
		}
	}
	return 0;
}

'PS(알고리즘 문제풀이) 관련 글 > PS일지' 카테고리의 다른 글

2024-03-01  (0) 2024.03.01
2024-02-29  (0) 2024.02.29
2024-02-27  (2) 2024.02.27
2024-02-26  (2) 2024.02.26
2024-02-25  (0) 2024.02.25