ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 2024-02-28
    PS(알고리즘 문제풀이) 관련 글/PS일지 2024. 2. 28. 22:47

    -분수의 합(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
Designed by Tistory.