728x90

www.acmicpc.net/problem/1963

 

1963번: 소수 경로

소수를 유난히도 좋아하는 창영이는 게임 아이디 비밀번호를 4자리 ‘소수’로 정해놓았다. 어느 날 창영이는 친한 친구와 대화를 나누었는데: “이제 슬슬 비번 바꿀 때도 됐잖아” “응 지금

www.acmicpc.net

최단 경로를 찾는 것이므로 BFS로 풀었다.

#include <iostream>
#include <vector>
#include <string>
#include <queue>
#include <map>
#include <cmath>
#include <algorithm>
using namespace std;

int main() {
	cin.tie(NULL);
	ios::sync_with_stdio(false);
	int testCase;
	cin >> testCase;
	vector<string> primeNumbers;
	map<string, int> map;
	for (int i = 1000; i <= 9999; i++) {
		int flag = true;
		for (int j = 2; j <= sqrt(i); j++) {
			if (i % j == 0) {
				flag = false;
				break;
			}
		}
		if (flag) {
			primeNumbers.push_back(to_string(i));
			map[to_string(i)] = primeNumbers.size() - 1;
		}
	}
	string from, to;
	for (int t = 0; t < testCase; t++) {
		vector<bool> visited(primeNumbers.size(), false);
		cin >> from >> to;
		queue<pair<string, int>> q;
		q.push(make_pair(from, 0));
		bool found = false;
		while (!q.empty()) {
			pair<string, int> cur = q.front();
			q.pop();
			if (cur.first == to) {
				cout << cur.second << '\n';
				found = true;
				break;
			}
			if (!visited[map[cur.first]]) {
				visited[map[cur.first]] = true;
				for (char i = '1'; i <= '9'; i++) {
					if (cur.first[0] == i)
						continue;
					string temp = cur.first;
					temp[0] = i;
					if (binary_search(primeNumbers.begin(), primeNumbers.end(), temp)) {
						if (!visited[map[temp]])
							q.push(make_pair(temp, cur.second + 1));
					}
				}
				for (char i = '0'; i <= '9'; i++) {
					if (cur.first[1] == i)
						continue;
					string temp = cur.first;
					temp[1] = i;
					if (binary_search(primeNumbers.begin(), primeNumbers.end(), temp)) {
						if (!visited[map[temp]])
							q.push(make_pair(temp, cur.second + 1));
					}
				}
				for (char i = '0'; i <= '9'; i++) {
					if (cur.first[2] == i)
						continue;
					string temp = cur.first;
					temp[2] = i;
					if (binary_search(primeNumbers.begin(), primeNumbers.end(), temp)) {
						if (!visited[map[temp]])
							q.push(make_pair(temp, cur.second + 1));
					}
				}
				for (char i = '0'; i <= '9'; i++) {
					if (cur.first[3] == i)
						continue;
					string temp = cur.first;
					temp[3] = i;
					if (binary_search(primeNumbers.begin(), primeNumbers.end(), temp)) {
						if (!visited[map[temp]])
							q.push(make_pair(temp, cur.second + 1));
					}
				}
			}
		}
		if (!found) {
			cout << "Impossible\n";
		}
	}
	return 0;
}
728x90
728x90

www.acmicpc.net/problem/11725

 

11725번: 트리의 부모 찾기

루트 없는 트리가 주어진다. 이때, 트리의 루트를 1이라고 정했을 때, 각 노드의 부모를 구하는 프로그램을 작성하시오.

www.acmicpc.net

BFS로 순회하면서 풀었다. 벡터 배열을 static으로 선언한 이유는 배열의 크기가 너무 커서 비주얼 스튜디오에서 돌리면 자꾸 런타임에러가 나면서 종료되어서 static으로 선언해서 힙에 할당하도록 해줬다.

제출할 때는 static 빼도 정답으로 나왔다.

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

int main() {
	cin.tie(NULL);
	ios::sync_with_stdio(false);
	int n;
	cin >> n;
	static vector<int> graph[100001];
	int from, to;
	for (int i = 0; i < n - 1; i++) {
		cin >> from >> to;
		graph[from].push_back(to);
		graph[to].push_back(from);
	}
	vector<bool> visited(n + 1, false);
	vector<int> parent(n + 1, -1);
	queue<int> q;
	q.push(1);
	parent[1] = 1;
	while (!q.empty()) {
		int cur = q.front();
		q.pop();
		if (!visited[cur]) {
			visited[cur] = true;
			for (int i = 0; i < graph[cur].size(); i++) {
				if (parent[graph[cur][i]] == -1) {
					parent[graph[cur][i]] = cur;
					q.push(graph[cur][i]);
				}
			}
		}
	}
	for (int i = 2; i <= n; i++) {
		cout << parent[i] << '\n';
	}
	return 0;
}
728x90

'알고리즘 문제' 카테고리의 다른 글

[백준] 14226번 이모티콘  (0) 2021.01.17
[백준] 1963번 소수 경로  (0) 2021.01.15
[백준] 2960번 에라토스테네스의 체  (0) 2021.01.14
[백준] 1890번 점프  (0) 2021.01.13
[백준] 1676번 팩토리얼 0의 개수  (0) 2021.01.13
728x90

www.acmicpc.net/problem/2960

 

2960번: 에라토스테네스의 체

2, 4, 6, 8, 10, 3, 9, 5, 7 순서대로 지워진다. 7번째 지워진 수는 9이다.

www.acmicpc.net

크기 n + 1짜리 bool 타입의 벡터 v를 선언하여 다음과 같이 true로 초기화시켰다.

그 다음 지울 때마다 false로 바꿔주었다.

그리고 지울 때마다 index를 1 증가시켰다. index는 몇 번째 지운 것인지를 나타낸다.

지우지 않은 숫자들 중에 가장 작은 수는 num에 저장했다.

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

int main() {
	int n, k;
	cin >> n >> k;
	vector<bool> v(n + 1, true);
	int index = 1;
	int answer = -1;
	while (true) {
		int num;
		for (int i = 2; i <= n; i++) {
			if (v[i]) {
				num = i;
				v[i] = false;
				if (index == k) {
					answer = i;
				}
				index++;
				break;
			}
		}
		if (answer != -1)
			break;
		int a = 2;
		while (a * num <= n) {
			if (v[a * num]) {
				v[a * num] = false;
				if (index == k) {
					answer = a * num;
					break;
				}
				index++;
			}
			a++;
		}
		if (answer != -1)
			break;
	}
	cout << answer;
	return 0;
}
728x90

'알고리즘 문제' 카테고리의 다른 글

[백준] 1963번 소수 경로  (0) 2021.01.15
[백준] 11725번 트리의 부모 찾기  (0) 2021.01.14
[백준] 1890번 점프  (0) 2021.01.13
[백준] 1676번 팩토리얼 0의 개수  (0) 2021.01.13
[백준] 1107번 리모컨  (0) 2021.01.11
728x90

www.acmicpc.net/problem/1890

 

1890번: 점프

첫째 줄에 게임 판의 크기 N (4 ≤ N ≤ 100)이 주어진다. 그 다음 N개 줄에는 각 칸에 적혀져 있는 수가 N개씩 주어진다. 칸에 적혀있는 수는 0보다 크거나 같고, 9보다 작거나 같은 정수이며, 가장

www.acmicpc.net

처음에는 다음과 같이 BFS로 풀었다. 하지만 메모리초과가 났다.

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

int main() {
	cin.tie(NULL);
	ios::sync_with_stdio(false);
	int n;
	cin >> n;
	vector<vector<int>> v(n, vector<int>(n));
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			cin >> v[i][j];
		}
	}
	vector<vector<long long>> answer(n, vector<long long>(n, 0));
	queue <pair<int, int>> q;
	q.push(make_pair(0, 0));
	while (!q.empty()) {
		pair<int, int> cur = q.front();
		q.pop();
		int row = cur.first;
		int col = cur.second;
		if (v[row][col] == 0)
			continue;
		if (row + v[row][col] < n) {
			if (row + v[row][col] != n - 1 || col != n - 1) {
				q.push(make_pair(row + v[row][col], col));
			}
			answer[row + v[row][col]][col]++;
		}
		if (col + v[row][col] < n) {
			if (row != n - 1 || col + v[row][col] != n - 1) {
				q.push(make_pair(row, col + v[row][col]));
			}
			answer[row][col + v[row][col]]++;
		}
	}
	cout << answer[n - 1][n - 1];
	return 0;
}

 

그래서 DP로 풀었다.

초등학교 고학년 때인지 중학교 때인지 다음과 같은 그림을 주면서

'출발점에서 도착점으로 가는 최단경로의 개수를 구하시오'

하는 문제 본 적 있을 것이다.

그 때 어떻게 풀었냐면

다들 이렇게 풀었을 것이다.

설명을 하자면

최단경로이므로 아래쪽 또는 오른쪽으로만 이동해야 한다.

따라서 위, 왼쪽의 숫자를 더한 것이 출발점에서 현 지점까지 오는 최단경로의 개수이다.

이것을 계속 반복하면 도착점까지의 최단경로의 개수를 구할 수 있다.

 

1890번 문제도 똑같다. 최단경로라는 말은 없지만 반드시 오른쪽이나 아래쪽으로만 이동해야 한다는 조건이 있다.

다만 거리가 이동 거리가 무조건 1이 아니라 특정 숫자만큼만 점프를 할 수 있다는 것 뿐이다.

입력으로

4
2 3 3 1
1 2 1 3
1 2 3 1
3 1 1 0

이렇게 들어왔다고 하자.

입력값으로 들어온 것은 벡터 v에 저장해주고 동적계획법으로 풀 때 값들을 저장할 벡터는 answer이라고 했다.

 

초기상태는 다음과 같다.

v는 입력받은 것이고 answer[0][0]은 1을 저장해주었다.

 

i = 0, j = 0일 때

위쪽과 왼쪽으로 가볼 곳이 없다.

 

i = 0, j = 1일 때

k = 1이면

 칸 왼쪽으로 가보면 v[0][0]은 1이 아니라 2이므로 안 된다.

왜 안 되냐? v에 저장된 값은 '몇 칸 점프할 수 있는지'이다. 따라서 v[0][0]은 2이므로 0행 0열에서는 두 칸 점프할 수 있다. 그런데 0행 0열에서 두 칸 점프해서는 0행 1열에 도달할 수 없다. 한 칸 점프해야만 도달할 수 있다. 즉 v[0][0]이 1일 때만 가능하다.

i = 0, j = 2일 때

k = 1이면

한 칸 왼쪽으로 가보면 v[0][1]은 1이 아니라 3이므로 안 된다.

k = 2이면

두 칸 왼쪽으로 가보면 v[0][0]은 2이므로 answer[0][0] 만큼을 더해준다. 즉, 1을 더해준다.

i = 0, j = 3일 때

k = 1이면

한 칸 왼쪽으로 가보면 v[0][1]은 1이 아니라 3이므로 안 된다.

k = 2이면

두 칸 왼쪽으로 가보면 v[0][1]은 2가 아니라 3이므로 안 된다.

k = 3이면

세  왼쪽으로 가보면 v[0][1]은 3이 아니라 2이므로 안 된다.

i = 1, j = 0일 때

k = 1이면

 칸 위쪽으로 가보면 v[0][0]은 1이 아니라 2이므로 안 된다.

i = 1, j = 1일 때

k = 1이면

 칸 위쪽으로 가보면 v[0][1]은 1이 아니라 3이므로 안 된다.

 칸 왼쪽으로 가보면 v[1][0]은 1이므로 answer[1][0] 만큼을 더해준다. 즉, 0을 더해준다.

i = 1, j = 2일 때

k = 1이면

 칸 위쪽으로 가보면 v[0][2]은 1이 아니라 3이므로 안 된다.

 칸 왼쪽으로 가보면 v[1][1]은 1이 아니라 2이므로 안 된다.

k = 2이면

 칸 왼쪽으로 가보면 v[1][0]은 2가 아니라 1이므로 안 된다.

i = 1, j = 3일 때

k = 1이면

 칸 위쪽으로 가보면 v[0][3]은 1이므로 answer[0][3] 만큼을 더해준다. 즉, 0을 더해준다.

 칸 왼쪽으로 가보면 v[1][2]은 1이므로 answer[1][2] 만큼을 더해준다. 즉, 0을 더해준다.

k = 2이면

 칸 왼쪽으로 가보면 v[1][1]은 2이므로 answer[1][1] 만큼을 더해준다. 즉, 0을 더해준다.

k = 3이면

 칸 왼쪽으로 가보면 v[1][0]은 3이 아니라 1이므로 안 된다

i = 2, j = 0일 때

k = 1이면

한 칸 위쪽으로 가보면 v[1][0]은 1이므로 answer[1][0] 만큼을 더해준다. 즉, 0을 더해준다.

k = 2이면

두 칸 위쪽으로 가보면 v[0][0]은 2이므로 answer[0][0] 만큼을 더해준다. 즉, 1을 더해준다.

i = 2, j = 1일 때

k = 1이면

한  위쪽으로 가보면 v[1][1]은 1이 아니라 2이므로 안 된다.

 칸 왼쪽으로 가보면 v[2][0]은 1이므로 answer[2][0] 만큼을 더해준다. 즉, 1을 더해준다.

k = 2이면

두 칸 위쪽으로 가보면 v[0][1]은 2가 아니라 3이므로 안 된다.

i = 2, j = 2일 때

k = 1이면

 칸 위쪽으로 가보면 v[1][2]는 1이므로 answer[1][2] 만큼을 더해준다. 즉, 0을 더해준다.

 칸 왼쪽으로 가보면 v[2][0]은 1 아니라 2이므로 안 된다.

k = 2이면

 칸 위쪽으로 가보면 v[0][2]은 2가 아니라 3이므로 안 된다.

 칸 왼쪽으로 가보면 v[2][0]은 2가 아니라 1이므로 안 된다.

i = 2, j = 3일 때

k = 1이면

 칸 위쪽으로 가보면 v[2][0]은 1이 아니라 3이므로 안 된다.

 칸 왼쪽으로 가보면 v[2][0]은 1이 아니라 3이므로 안 된다.

k = 2이면

 칸 위쪽으로 가보면 v[2][0]은 2가 아니라 1이므로 안 된다.

 칸 왼쪽으로 가보면 v[2][1]은 2이므로 answer[2][1] 만큼을 더해준다. 즉, 1을 더해준다.

k = 3이면

 칸 왼쪽으로 가보면 v[2][0]은 3이 아니라 1이므로 안 된다.

i = 3, j = 0일 때

k = 1이면

 칸 위쪽으로 가보면 v[2][0]은 1이므로 answer[2][0] 만큼을 더해준다. 즉, 1을 더해준다.

k = 2이면

 칸 위쪽으로 가보면 v[1][0]은 2가 아니라 1이므로 안 된다.

k = 3이면

 칸 위쪽으로 가보면 v[0][0]은 3이 아니라 2이므로 안 된다.

i = 3, j = 1일 때

k = 1이면

 칸 위쪽으로 가보면 v[2][1]은 1이 아니라 2이므로 안 된다.

 칸 왼쪽으로 가보면 v[3][0]은 1이 아니라 3이므로 안 된다.

k = 2이면

 칸 위쪽으로 가보면 v[1][1]은 2이므로 answer[1][1] 만큼을 더해준다. 즉, 0을 더해준다.

k = 3이면

 칸 위쪽으로 가보면 v[0][1]은 3므로 answer[0][1] 만큼을 더해준다. 즉, 0을 더해준다.

i = 3, j = 2일 때

k = 1이면

 칸 위쪽으로 가보면 v[2][2]은 1이 아니라 3이므로 안 된다.

 칸 왼쪽으로 가보면 v[3][1]은 1이므로 answer[3][1] 만큼을 더해준다. 즉, 0을 더해준다.

k = 2이면

 칸 위쪽으로 가보면 v[1][2]은 2가 아니라 1이므로 안 된다.

 칸 왼쪽으로 가보면 v[3][0]은 2가 아니라 3이므로 안 된다.

k = 3이면

 칸 위쪽으로 가보면 v[0][2]은 3이므로 answer[0][2] 만큼을 더해준다. 즉, 1을 더해준다.

i = 3, j = 3일 때

k = 1이면

 칸 위쪽으로 가보면 v[2][3]은 1이므로 answer[2][3] 만큼을 더해준다. 즉, 1을 더해준다.

 칸 왼쪽으로 가보면 v[3][2]은 1이므로 answer[3][2] 만큼을 더해준다. 즉, 1을 더해준다.

k = 2이면

 칸 위쪽으로 가보면 v[1][3]은 2가 아니라 3이므로 안 된다.

 칸 왼쪽으로 가보면 v[3][1]은 2가 아니라 1이므로 안 된다.

k = 3이면

 칸 위쪽으로 가보면 v[0][3]은 3 아니라 1이므로 안 된다..

 칸 왼쪽으로 가보면 v[3][0]은 3이므로 answer[3][0] 만큼을 더해준다. 즉, 1을 더해준다.

이해가 안 간다면 다음 동영상을 참고하면 된다. (혼을 갈아서 만든 영상입니다..)

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

int main() {
	cin.tie(NULL);
	ios::sync_with_stdio(false);
	int n;
	cin >> n;
	vector<vector<int>> v(n, vector<int>(n));
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			cin >> v[i][j];
		}
	}
	vector<vector<long long>> answer(n, vector<long long>(n, 0));
	answer[0][0] = 1;
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			for (int k = 1; k <= i; k++) {
				if (v[i - k][j] == k) {
					answer[i][j] += answer[i - k][j];
				}
			}
			for (int k = 1; k <= j; k++) {
				if (v[i][j - k] == k) {
					answer[i][j] += answer[i][j - k];
				}
			}
		}
	}
	cout << answer[n - 1][n - 1];
	return 0;
}

728x90
728x90

www.acmicpc.net/problem/1676

 

1676번: 팩토리얼 0의 개수

N!에서 뒤에서부터 처음 0이 아닌 숫자가 나올 때까지 0의 개수를 구하는 프로그램을 작성하시오.

www.acmicpc.net

N!을 직접 구하는 것은 숫자가 기하급수적으로 커지므로 직접 구하면 아마 오버플로우가 날 것이다.

따라서 다른 방법을 사용했다.

어떤 숫자가 뒤에서부터 0이 1개 나온다는 것은 10의 배수라는 것이다.

어떤 숫자가 뒤에서부터 0이 연속으로 2개 나온다는 것은 100의 배수라는 것이다.

어떤 숫자가 뒤에서부터 0이 연속으로 3개 나온다는 것은 1000의 배수라는 것이다.

그러므로 소인수분해를 하여 2와 5의 개수를 세어주면 된다.

2가 6개, 5가 3개면 10을 3개 만들 수 있다.

2가 100개이더라도 5가 3개이면 10을 3개만 만들 수 있다.

2가 5개, 5가 100개여도 10을 5개 만들 수 있다.

N부터 N-1, N-2, N-3, ... , 2, 1까지 각각을 소인수분해를 하여 2의 개수를 twoCount에, 5의 개수를 fiveCount에 저장하고 twoCount와 fiveCount 중에 더 작은 값이 10을 몇 개 만들 수 있는지를 뜻하므로 min(twoCount, fiveCount)를 출력하도록 했다.

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

int main() {
	int n;
	cin >> n;
	int twoCount = 0;
	int fiveCount = 0;
	for (int i = 1; i <= n; i++) {
		int num = i;
		while (num % 2 == 0) {
			num /= 2;
			twoCount++;
		}
		while (num % 5 == 0) {
			num /= 5;
			fiveCount++;
		}
	}
	cout << min(twoCount, fiveCount);
	return 0;
}
728x90

'알고리즘 문제' 카테고리의 다른 글

[백준] 2960번 에라토스테네스의 체  (0) 2021.01.14
[백준] 1890번 점프  (0) 2021.01.13
[백준] 1107번 리모컨  (0) 2021.01.11
[백준] 1013번 Contact  (0) 2021.01.08
[백준] 10974번 모든 순열  (0) 2021.01.05
728x90

www.acmicpc.net/problem/1107

 

1107번: 리모컨

첫째 줄에 수빈이가 이동하려고 하는 채널 N (0 ≤ N ≤ 500,000)이 주어진다.  둘째 줄에는 고장난 버튼의 개수 M (0 ≤ M ≤ 10)이 주어진다. 고장난 버튼이 있는 경우에는 셋째 줄에는 고장난 버튼

www.acmicpc.net

버튼 10개가 모두 고장났을 때를 반드시 처리해줘야 한다. 안 그러면 무한루프에 빠지게 된다.

1씩 늘리거나 줄이면서 이 숫자를 리모컨으로 입력할 수 있을 때까지 반복한다.

입력할 수 있으면 while문에서 나온다. 그리고 100에서 이동하는 것과 버튼으로 누른 후 + 버튼이나 - 버튼으로 이동하는 것 중 어떤 것이 더 빠른지를 체크하면 된다.

int를 string으로 변경하는 것은 <string> 헤더에 있는 to_string() 함수를 사용하여 해당 채널로 가려면 숫자 버튼을 몇 번 눌러야 하는지 알아내었다.

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

int main() {
	cin.tie(NULL);
	ios::sync_with_stdio(false);
	int n, m, num;
	vector<bool> v(10, true);
	cin >> n >> m;
	int ans;
	for (int i = 0; i < m; i++) {
		cin >> num;
		v[num] = false;
	}
	int k = 0;
	bool up;
	if (m < 10) {
		while (true) {
			int divider = 1;
			bool answer = true;
			if (n - k > 0) {
				while (true) {
					if ((n - k) / divider == 0) {
						break;
					}
					if (!v[(n - k) / divider % 10]) {
						answer = false;
						break;
					}
					divider *= 10;
				}
				if (answer) {
					ans = k;
					up = false;
					break;
				}
			}
			else if (n - k == 0) {
				if (!v[0]) {
					answer = false;
				}
				if (answer) {
					ans = k;
					up = false;
					break;
				}
			}
			answer = true;
			if (n + k == 0) {
				if (!v[0]) {
					answer = false;
				}
				if (answer) {
					ans = k;
					up = true;
					break;
				}
			}
			divider = 1;
			while (true) {
				if ((n + k) / divider == 0)
					break;
				if (!v[(n + k) / divider % 10]) {
					answer = false;
					break;
				}
				divider *= 10;
			}
			if (answer) {
				ans = k;
				up = true;
				break;
			}
			k++;
		}
	}
	else {
		cout << abs(n - 100);
		return 0;
	}
	cout << min((int)(ans + to_string((up ? n + k : n - k)).size()), abs(n - 100));
	return 0;
}
728x90

'알고리즘 문제' 카테고리의 다른 글

[백준] 1890번 점프  (0) 2021.01.13
[백준] 1676번 팩토리얼 0의 개수  (0) 2021.01.13
[백준] 1013번 Contact  (0) 2021.01.08
[백준] 10974번 모든 순열  (0) 2021.01.05
[백준] 1992번 쿼드트리  (0) 2021.01.05
728x90

www.acmicpc.net/problem/1013

 

1013번: Contact

입력의 첫 줄에는 테스트 케이스의 개수 T가 주어진다. 그 다음 줄부터 각각의 테스트 케이스에 대해 전파를 표현하는, { 0, 1 }만으로 이루어진 문자열이 공백 없이 주어진다. 문자열 길이는 (1 ≤

www.acmicpc.net

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

int main() {
	cin.tie(NULL);
	ios::sync_with_stdio(false);
	int n;
	string s;
	cin >> n;
	for (int t = 0; t < n; t++) {
		cin >> s;
		vector<pair<char, int>> v;
		v.push_back(make_pair(s[0], 1));
		for (int i = 1; i < s.size(); i++) {
			if (s[i] == v[v.size() - 1].first) {
				v[v.size() - 1].second++;
			}
			else {
				v.push_back(make_pair(s[i], 1));
			}
		}
		int index = 0;
		while (index < v.size()) {
			if (v[index].first == '1') { //(100+1+) 타입일 때
				if (v[index].second == 1 && index + 1 < v.size() && v[index + 1].first == '0' && v[index + 1].second >= 2 && index + 2 < v.size() && v[index + 2].first == '1') {
					index += 3;
				}
				else {
					break;
				}
			}
			else { // (01) 타입일 때
				if (v[index].second == 1 && index + 1 < v.size() && v[index + 1].first == '1' && v[index + 1].second >= 1) {
					if (v[index + 1].second > 1) {
						v.insert(v.begin() + index + 2, make_pair(v[index + 1].first, v[index + 1].second - 1));
					}
					index += 2;
				}
				else {
					if (index - 1 >= 0 && v[index - 1].first == '1' && v[index - 1].second > 1) {
						v.insert(v.begin() + index, make_pair('1', 1));
					}
					else {
						break;
					}
				}
			}
		}
		cout << (index == v.size() ? "YES\n" : "NO\n");
	}
	return 0;
}

문자열이 들어오면 일단 이것을 가지고 pair<char, int> 타입의 벡터 v를 만들어주었다.

코드에서 벡터 v를 만들어주는 부분이

v.push_back(make_pair(s[0], 1));
for (int i = 1; i < s.size(); i++) {
	if (s[i] == v[v.size() - 1].first) {
		v[v.size() - 1].second++;
	}
	else {
		v.push_back(make_pair(s[i], 1));
	}
}

이 부분이다.

pair의 첫 번째 원소에는 s[i]를, 두 번째 원소에는 s[i]가 연속으로 몇 개 나오는지 그 개수를 저장하도록 했다.

예를 들어 10011001이라는 문자열이 들어온다면 벡터 v는 다음과 같이 만들어진다.

index = 0부터 시작해서 벡터를 체크한다.

v[0].first가 '1'이면 (100+1+) 타입이고 v[0].first가 '0'이면 (01) 타입이다.

이것을 체크하는 부분이

if (v[index].first == '1') {
	...
}
else {
	...
}

이 부분이다.

여기에서 v[0].first는 '1'이므로 (100+1+) 타입이다.

(100+1+) 타입은 11개 나오고 02개 이상 나와야 하고 그 다음에는 1이 1개 이상 나와야 한다.

즉, v[0].second는 1이어야 하고 v[1].first는 '0', v[1].second는 2 이상이어야 한다. 그리고 v[2].first는 '1'이어야 한다. 

이 조건을 표현한 것이

if (v[index].second == 1 && index + 1 < v.size() && v[index + 1].first == '0' && v[index + 1].second >= 2 && index + 2 < v.size() && v[index + 2].first == '1')

이 부분이다.

이 조건들을 만족시키므로 index를 3 증가시킨다. 그러면 index는 3이 된다.

(그런데 문제가 있다. 10011 /001 이렇게 끊긴 것이다. 1001/1001 이렇게 끊겨야 하는데 말이다.)

그래도 일단 index가 3이 되었으니 v[3]부터 다시 체크한다.

v[3].first가 '0'이므로 (01) 타입이다.

(01) 타입은 01개 나오고 11개 나와야 한다.

따라서 v[3].second는 1이어야 하고 v[4].first는 '1', v[4].second는 1이어야 한다.

이것을 체크하는 부분이

if (v[index].second == 1 && index + 1 < v.size() && v[index + 1].first == '1' && v[index + 1].second >= 1)

이 부분이다. (v[index + 1].second == 1이 아니라 v[index + 1].second >= 1인 이유는 뒤에서 설명합니다!)

그런데 v[3].second는 2이므로 v[index].second == 1이라는 조건에 맞지 않는다.

아무튼 (01) 타입의 조건을 충족시키지 못하므로 if문에 걸리지 못하고 else문에 걸리게 된다.

그러면 10011001은 NO인가?? 아니다. YES를 출력해야 한다.

1001/1001/ 이렇게 끊어져야 하는데 10011/001 이렇게 잘못 끊어져서 이런 문제가 발생했다. 따라서 else문 안에서 처리해주어야 한다.

하나 앞에서 '1'이 2개 이상이라면 앞에서 '1' 한개를 빌려오면 된다.

(100+1+) 타입에서는 마지막에는 1이 한 개 오든 두 개 오든 100개가 오든 상관없이 조건을 충족하기 때문이다.

따라서 else문 안에서 v[index - 1].first가 '1'이고 v[index - 1].second가 1보다 큰지를 체크해준다. 

if (index - 1 >= 0 && v[index - 1].first == '1' && v[index - 1].second > 1)

v[2].first는 '1'이고 v[2].second는 2이므로 이 if문에 걸리게 된다.

이 if문 안에서는 

v.insert(v.begin() + index, make_pair('1', 1));

벡터 v에 ('1', 1)을 끼워넣는 것이다.

즉 벡터 v는 다음과 같이 된다.

앞에서 '1' 하나를 빌려왔으므로 사실 v[2]는 ('1', 1)로 바뀌어야 하는데 이미 지나온 index이므로 그냥 둬도 상관없다.

아무튼 index는 그대로 3이다.

여기에서 v[3].first는 '1'이므로 (100+1+) 타입이다.

(100+1+) 타입은 1 1개 나오고 0 2개 이상 나와야 하고 그 다음에는 1이 1개 이상 나와야 한다.

즉, v[3].second는 1이어야 하고 v[4].first는 '0', v[4].second는 2 이상이어야 한다. 그리고 v[5].first는 '1'이어야 한다. 

이 조건을 모두 만족시키므로 index를 3 증가시킨다. 그러면 index는 6이 된다.

벡터의 크기는 6이므로 

while (index < v.size())

이 조건에 맞지 않으므로 index가 6인채로 while문을 빠져나오게 된다.

v.size()인 6과 index인 6이 일치하므로 YES를 출력한다.

v.size()와 index가 일치하지 않는다는 것은 정상적으로 while문을 빠져나온 것이 아니라 조건에 맞지 않아 break로 빠져나온 것이기 때문에 NO를 출력한다.

 

또 다른 예로 01100011이 입력으로 들어왔다고 하자.

이것은 01/100011으로 조건을 충족하므로 YES를 출력해야 한다.

벡터 v는 다음과 같다.

index는 0부터 시작한다.

v[0].first가 '0'이므로 (01) 타입이다.

(01) 타입은 0 1개 나오고 1 1개 나와야 한다.

따라서 v[0].second는 1이어야 하고 v[1].first는 '1', v[1].second는 1이어야 한다.

그런데 v[1].second는 2이다.

(01) 타입의 조건이 맞는지 체크하는 부분인

if (v[index].second == 1 && index + 1 < v.size() && v[index + 1].first == '1' && v[index + 1].second >= 1)

이 부분에서 v[index + 1].second == 1이 아니라 v[index + 1].second >= 1인 이유가 바로 이것이다.

v[index + 1].second > 1이면 '1'을 하나만 쓰고 나머지는 뒤로 넘기는 것이다.

사실 '1'을 하나만 가져오고 나머지 '1'들은 뒤로 넘기는 것이므로 ('1', 1)이 추가되고 v[1].second는 1로 바뀌어야 하는데 이미 지난 index이므로 그대로 둬도 상관없다.

이렇게 하고 index를 2 증가시킨다.

이제 index는 2이다.

여기에서 v[2].first는 '1'이므로 (100+1+) 타입이다.

(100+1+) 타입은 1 1개 나오고 0 2개 이상 나와야 하고 그 다음에는 1이 1개 이상 나와야 한다.

즉, v[2].second는 1이어야 하고 v[3].first는 '0', v[3].second는 2 이상이어야 한다. 그리고 v[4].first는 '1'이어야 한다. 

이 조건을 모두 만족시키므로 index를 3 증가시킨다. 그러면 index는 5이 된다.

index가 5가 되면 while문의 조건인 index < v.size()에 맞지 않으므로 while문을 빠져나온다.

index가 5인채로 빠져나왔고 v.size()는 5이므로 YES를 출력한다.

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

int main() {
	cin.tie(NULL);
	ios::sync_with_stdio(false);
	int n;
	string s;
	cin >> n;
	for (int t = 0; t < n; t++) {
		cin >> s;
		vector<pair<char, int>> v;
		v.push_back(make_pair(s[0], 1));
		for (int i = 1; i < s.size(); i++) {
			if (s[i] == v[v.size() - 1].first) {
				v[v.size() - 1].second++;
			}
			else {
				v.push_back(make_pair(s[i], 1));
			}
		}
		int index = 0;
		while (index < v.size()) {
			if (v[index].first == '1') { //(100+1+) 타입일 때
				if (v[index].second == 1 && index + 1 < v.size() && v[index + 1].first == '0' && v[index + 1].second >= 2 && index + 2 < v.size() && v[index + 2].first == '1') {
					index += 3;
				}
				else {
					break;
				}
			}
			else { // (01) 타입일 때
				if (v[index].second == 1 && index + 1 < v.size() && v[index + 1].first == '1' && v[index + 1].second >= 1) {
					if (v[index + 1].second > 1) {
						v.insert(v.begin() + index + 2, make_pair(v[index + 1].first, v[index + 1].second - 1));
					}
					index += 2;
				}
				else {
					if (index - 1 >= 0 && v[index - 1].first == '1' && v[index - 1].second > 1) {
						v.insert(v.begin() + index, make_pair('1', 1));
					}
					else {
						break;
					}
				}
			}
		}
		cout << (index == v.size() ? "YES\n" : "NO\n");
	}
	return 0;
}
728x90

'알고리즘 문제' 카테고리의 다른 글

[백준] 1676번 팩토리얼 0의 개수  (0) 2021.01.13
[백준] 1107번 리모컨  (0) 2021.01.11
[백준] 10974번 모든 순열  (0) 2021.01.05
[백준] 1992번 쿼드트리  (0) 2021.01.05
[백준] 1074번 Z  (0) 2021.01.04
728x90

www.acmicpc.net/problem/10974

 

10974번: 모든 순열

N이 주어졌을 때, 1부터 N까지의 수로 이루어진 순열을 사전순으로 출력하는 프로그램을 작성하시오.

www.acmicpc.net

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

int n;

void permutation(int num, vector<bool> visited, vector<int> result) {
	if (num == n) {
		for (int i = 0; i < n; i++) {
			cout << result[i] << " ";
		}
		cout << '\n';
		return;
	}
	for (int i = 0; i < n; i++) {
		if (!visited[i]) {
			result[num] = i + 1;
			visited[i] = true;
			permutation(num + 1, visited, result);
			visited[i] = false;
		}
	}
}

int main() {
	cin.tie(NULL);
	ios::sync_with_stdio(false);
	cin >> n;
	permutation(0, vector<bool>(n, false), vector<int>(n));
	return 0;
}
728x90

'알고리즘 문제' 카테고리의 다른 글

[백준] 1107번 리모컨  (0) 2021.01.11
[백준] 1013번 Contact  (0) 2021.01.08
[백준] 1992번 쿼드트리  (0) 2021.01.05
[백준] 1074번 Z  (0) 2021.01.04
[백준] 1004번 어린 왕자  (0) 2021.01.03
728x90

www.acmicpc.net/problem/1992

 

1992번: 쿼드트리

첫째 줄에는 영상의 크기를 나타내는 숫자 N 이 주어진다. N 은 언제나 2의 제곱수로 주어지며, 1 ≤ N ≤ 64의 범위를 가진다. 두 번째 줄부터는 길이 N의 문자열이 N개 들어온다. 각 문자열은 0 또

www.acmicpc.net

문제에 주어진대로 그대로 재귀로 구현하면 된다. 

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

vector<string> v;

void compress(int row, int col, int size) {
	if (size == 1) {

	}
	char first = v[row][col];
	bool flag = true;
	for (int i = row; i < row + size; i++) {
		for (int j = col; j < col + size; j++) {
			if (v[i][j] != first) {
				flag = false;
				break;
			}
		}
		if (!flag) {
			break;
		}
	}
	if (!flag) {
		cout << '(';
		compress(row, col, size / 2);
		compress(row, col + size / 2, size / 2);
		compress(row + size / 2, col, size / 2);
		compress(row + size / 2, col + size / 2, size / 2);
		cout << ')';
	}
	else {
		cout << first;
	}
}

int main() {
	cin.tie(NULL);
	ios::sync_with_stdio(false);
	int n;
	cin >> n;
	v = vector<string>(n);
	for (int i = 0; i < n; i++) {
		cin >> v[i];
	}
	compress(0, 0, n);
	return 0;
}
728x90

'알고리즘 문제' 카테고리의 다른 글

[백준] 1013번 Contact  (0) 2021.01.08
[백준] 10974번 모든 순열  (0) 2021.01.05
[백준] 1074번 Z  (0) 2021.01.04
[백준] 1004번 어린 왕자  (0) 2021.01.03
[백준] 11866번 요세푸스 문제 0  (0) 2021.01.03
728x90

www.acmicpc.net/problem/1074

 

1074번: Z

한수는 크기가 2N × 2N인 2차원 배열을 Z모양으로 탐색하려고 한다. 예를 들어, 2×2배열을 왼쪽 위칸, 오른쪽 위칸, 왼쪽 아래칸, 오른쪽 아래칸 순서대로 방문하면 Z모양이다. 만약, N > 1이 라서

www.acmicpc.net

전에 풀었던 1074번...

breakcoding.tistory.com/298

 

[백준] 1074번 Z

https://www.acmicpc.net/problem/1074 1074번: Z 한수는 2차원 배열 (항상 2^N * 2^N 크기이다)을 Z모양으로 탐색하려고 한다. 예를 들어, 2*2배열을 왼쪽 위칸, 오른쪽 위칸, 왼쪽 아래칸, 오른쪽 아래칸 순서대..

breakcoding.tistory.com

재채점으로 시간초과가 되었다.

머리 안 쓰고 문제에 나와있는 그대로 재귀로 풀었었는데 시간제한이 0.5초로 변경되면서 시간초과로 결과가 바뀌었다.

그래서 다시 풀었다.

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

int main() {
	cin.tie(NULL);
	ios::sync_with_stdio(false);
	int n, r, c;
	cin >> n >> r >> c;
	n = pow(2, n);
	int index = 0;
	while (true) {
		if (n == 1) {
			break;
		}
		if (r < n / 2 && c < n / 2) {
		}
		else if (r < n / 2 && c >= n / 2) {
			c -= n / 2;
			index += pow(n / 2, 2);
		}
		else if (r >= n / 2 && c < n / 2) {
			r -= n / 2;
			index += pow(n / 2, 2) * 2;
		}
		else {
			r -= n / 2;
			c -= n / 2;
			index += pow(n / 2, 2) * 3;
		}
		n /= 2;
	}
	cout << index;
	return 0;
}
728x90

'알고리즘 문제' 카테고리의 다른 글

[백준] 10974번 모든 순열  (0) 2021.01.05
[백준] 1992번 쿼드트리  (0) 2021.01.05
[백준] 1004번 어린 왕자  (0) 2021.01.03
[백준] 11866번 요세푸스 문제 0  (0) 2021.01.03
[백준] 2217번 로프  (0) 2021.01.02

+ Recent posts