728x90

www.acmicpc.net/problem/1004

 

1004번: 어린 왕자

입력의 첫 줄에는 테스트 케이스의 개수 T가 주어진다. 그 다음 줄부터 각각의 테스트케이스에 대해 첫째 줄에 출발점 (x1, y1)과 도착점 (x2, y2)이 주어진다. 두 번째 줄에는 행성계의 개수 n이 주

www.acmicpc.net

n개의 행성계의 범위를 입력받을 때 출발점이 해당 행성계에 포함되는지, 도착점이 해당 행성계에 포함되는지를 벡터에 저장해주었다. 출발점이 포함되는지 여부는 v[i].first에, 도착점이 포함되는지 여부는 v[i].second에 저장해주었다.

포함되는지 아닌지는 행성계의 중심과 출발점 (또는 도착점) 사이의 거리가 행성계의 반지름의 길이보다 큰지 아닌지를 판단해주었다.

예를 들어 행성계의 중심이 (a, b), 반지름이 r이고 출발점이 (c, d)일 때

두 점 (a, b)와 (c, d) 사이의 거리인 √(a - c)^2 + (b - d)^2가 r보다 크면 출발점 (c, d)는 행성계에 포함되지 않는다.

하지만 정수에서 루트를 씌우면 실수가 되어 부정확해진다. 따라서 그냥 (a - c)^2 + (b - d)^2와 r^2을 비교해주었다.

그렇게 출발점과 도착점이 행성계에 포함되는지 아닌지 n개의 행성계를 판단하여 포함되면 true, 포함되지 않으면 false를 저장해준다.

포함 여부가 모두 일치한다면 출발점과 도착점은 같은 행성계에 있으므로 진입, 이탈 횟수는 0이다.

포함 여부가 하나만 다르다면 진입/이탈 횟수는 1이 된다. 이런 식으로 풀었다.

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

int main() {
	cin.tie(NULL);
	ios::sync_with_stdio(false);
	int testCase;
	cin >> testCase;
	int x1, x2, y1, y2, n, cx, cy, r, cnt;
	for (int t = 0; t < testCase; t++) {
		cnt = 0;
		cin >> x1 >> y1 >> x2 >> y2 >> n;
		vector<pair<bool, bool>> v(n);
		for (int i = 0; i < n; i++) {
			cin >> cx >> cy >> r;
			if (pow(cx - x1, 2) + pow(cy - y1, 2) > r * r) {
				v[i].first = false;
			}
			else {
				v[i].first = true;
			}
			if (pow(cx - x2, 2) + pow(cy - y2, 2) > r * r) {
				v[i].second = false;
			}
			else {
				v[i].second = true;
			}
		}
		for (int i = 0; i < n; i++) {
			if (v[i].first != v[i].second) {
				cnt++;
			}
		}
		cout << cnt << '\n';
	}
	return 0;
}
728x90

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

[백준] 1992번 쿼드트리  (0) 2021.01.05
[백준] 1074번 Z  (0) 2021.01.04
[백준] 11866번 요세푸스 문제 0  (0) 2021.01.03
[백준] 2217번 로프  (0) 2021.01.02
[백준] 10799번 쇠막대기  (0) 2021.01.02
728x90

www.acmicpc.net/problem/11866

 

11866번: 요세푸스 문제 0

첫째 줄에 N과 K가 빈 칸을 사이에 두고 순서대로 주어진다. (1 ≤ K ≤ N ≤ 1,000)

www.acmicpc.net

벡터의 원소를 직접 제거해가면서 풀었다.

주의할 점은 벡터의 크기가 점점 줄어들기 때문에 index가 벡터의 범위를 넘어가지 않게 % 연산자를 이용해 조정해줘야 한다.

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

int main() {
	int n, k;
	cin >> n >> k;
	vector<int> v(n);
	for (int i = 0; i < n; i++) {
		v[i] = i + 1;
	}
	int index = 0;
	while (!v.empty()) {
		if (v.size() == n) {
			cout << '<';
		}
		index += (k - 1);
		index %= v.size();
		cout << v[index];
		v.erase(v.begin() + index);
		if (v.empty()) {
			cout << '>';
		}
		else {
			cout << ", ";
		}
	}
	return 0;
}
728x90

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

[백준] 1074번 Z  (0) 2021.01.04
[백준] 1004번 어린 왕자  (0) 2021.01.03
[백준] 2217번 로프  (0) 2021.01.02
[백준] 10799번 쇠막대기  (0) 2021.01.02
[백준] 5582번 공통 부분 문자열  (0) 2020.09.10
728x90

www.acmicpc.net/problem/2217

 

2217번: 로프

N(1 ≤ N ≤ 100,000)개의 로프가 있다. 이 로프를 이용하여 이런 저런 물체를 들어올릴 수 있다. 각각의 로프는 그 굵기나 길이가 다르기 때문에 들 수 있는 물체의 중량이 서로 다를 수도 있다. 하

www.acmicpc.net

이 문제의 정답률이 42%밖에 되지 않는 이유는 다들 '문제를 제대로 읽지 않아서'인 것 같다.

'모든 로프를 사용해야 할 필요는 없으며, 임의로 몇 개의 로프를 골라서 사용해도 된다.'

위 문장만 유의하면 된다.

위의 문장이 없다면 최솟값 * N인데 모든 로프를 사용해야할 필요가 없으므로 여러 가지 경우의 수를 생각해봐야 한다.

만약 입력이 다음과 같이 주어졌을 때

3
10
20
50

모든 로프를 사용해야 한다면 답은 3 * 10 = 30이 되겠지만

모든 로프를 사용해야 할 필요가 없다면 다음과 같은 경우의 수가 있다.

로프 3개를 쓴다면 들 수 있는 최대 중량은 10 * 3 = 30

로프 2개를 쓴다면 들 수 있는 최대 중량은 20 * 2 = 40

로프 1개를 쓴다면 들 수 있는 최대 중량은 50 * 1 = 50

이므로 답은 50이 된다.

따라서 로프가 버틸 수 있는 중량을 벡터에 입력받은 후 오름차순으로 정렬한 후 하나 씩 제외하면서 최댓값을 구했다.

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

int main() {
	cin.tie(NULL);
	ios::sync_with_stdio(false);
	int n;
	vector<int> v;
	cin >> n;
	int weight;
	for (int i = 0; i < n; i++) {
		cin >> weight;
		v.push_back(weight);
	}
	sort(v.begin(), v.end());
	int maxWeight = 0;
	for (int i = 0; i < n; i++) {
		if (v[i] * (n - i) > maxWeight) {
			maxWeight = v[i] * (n - i);
		}
	}
	cout << maxWeight;
	return 0;
}
728x90

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

[백준] 1004번 어린 왕자  (0) 2021.01.03
[백준] 11866번 요세푸스 문제 0  (0) 2021.01.03
[백준] 10799번 쇠막대기  (0) 2021.01.02
[백준] 5582번 공통 부분 문자열  (0) 2020.09.10
[백준] 3055번 탈출  (0) 2020.09.04
728x90

www.acmicpc.net/problem/10799

 

10799번: 쇠막대기

여러 개의 쇠막대기를 레이저로 절단하려고 한다. 효율적인 작업을 위해서 쇠막대기를 아래에서 위로 겹쳐 놓고, 레이저를 위에서 수직으로 발사하여 쇠막대기들을 자른다. 쇠막대기와 레이저

www.acmicpc.net

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

int main() {
	string s;
	int cnt = 0; // 현 시점에 있는 쇠막대기
	int stickNum = 0; // 현재까지 잘린 막대기 조각 개수
	cin >> s;
	for (int i = 0; i < s.size(); i++) {
		if (s[i] == '(') {
			if (i < s.size() - 1 && s[i + 1] == ')') { // 레이저일때 -> 상황 A
				stickNum += cnt;
				i++; // 레이저이므로 다음 s[i]는 ')'이므로 다음 문자는 뛰어넘음
			}
			else { // 여는 괄호일 때 -> 상황 B
				cnt++;
			}
		}
		else { // 닫는 괄호일 때 -> 상황 C
			cnt--;
			stickNum++;
		}
	}
	cout << stickNum;
	return 0;
}

일단 문자열로 받은 다음 문자열의 길이만큼 for문을 돌면서 순차적으로 그 시점에 있는 쇠막대기의 개수와 그 시점에서 현재까지 잘린 막대기 조각의 개수를 세었다.

현 시점에 있는 쇠막대기의 개수: cnt

현재까지 잘린 막대기 조각의 개수: stickNum

()(((()())(())()))(())

입력이 위와 같이 들어왔을 때

위와 같이 동작한다. 따라서 답은 17이 된다.

상황 A는 if문 안에서의 if문 (레이저일 때)

상황 B는 if문 안에서의 else문 (여는 괄호일 때)

상황 C는 else문 (닫는 괄호일 때)

 

코드에 조금 더 충실하게 표를 그리자면

위와 같다. 레이저일 경우 i++로 건너뛰는 것을 표현해주었다.

728x90

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

[백준] 11866번 요세푸스 문제 0  (0) 2021.01.03
[백준] 2217번 로프  (0) 2021.01.02
[백준] 5582번 공통 부분 문자열  (0) 2020.09.10
[백준] 3055번 탈출  (0) 2020.09.04
[백준] 13904번 과제  (0) 2020.09.02
728x90

www.acmicpc.net/problem/5582

 

5582번: 공통 부분 문자열

두 문자열이 주어졌을 때, 두 문자열에 모두 포함된 가장 긴 공통 부분 문자열을 찾는 프로그램을 작성하시오. 어떤 문자열 s의 부분 문자열 t란, s에 t가 연속으로 나타나는 것을 말한다. 예를 들

www.acmicpc.net

처음에는 LCS 문제인 줄 알았는데 연속하는 공통된 문자열을 구하는 것이었다. LCS와 비슷하게 동적 계획법으로 풀었다.

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

int main() {
	cin.tie(NULL);
	ios_base::sync_with_stdio(false);
	string s1, s2;
	cin >> s1 >> s2;
	int maxDp = 0;
	vector<vector<int>> dp(s1.length() + 1, vector<int>(s2.length() + 1));
	for (int i = 1; i <= s1.length(); i++) {
		for (int j = 1; j <= s2.length(); j++) {
			if (s1[i - 1] == s2[j - 1]) {
				dp[i][j] = dp[i - 1][j - 1] + 1;
			}
			else {
				dp[i][j] = 0;
			}
			if (dp[i][j] > maxDp)
				maxDp = dp[i][j];
		}
	}
	cout << maxDp;
	return 0;
}
728x90

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

[백준] 2217번 로프  (0) 2021.01.02
[백준] 10799번 쇠막대기  (0) 2021.01.02
[백준] 3055번 탈출  (0) 2020.09.04
[백준] 13904번 과제  (0) 2020.09.02
[백준] 1038번 감소하는 수  (0) 2020.09.01
728x90

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

 

3055번: 탈출

사악한 암흑의 군주 이민혁은 드디어 마법 구슬을 손에 넣었고, 그 능력을 실험해보기 위해 근처의 티떱숲에 홍수를 일으키려고 한다. 이 숲에는 고슴도치가 한 마리 살고 있다. 고슴도치는 제��

www.acmicpc.net

가중치가 없는 최단경로를 구하는 것이기 때문에 BFS로 풀었다. 한 가지 주의할 점은 큐에서 빼낼 때 한 번에 하나씩 빼내는 것이 아니라 같은 시점에 큐에 넣어진 것들은 한번에 큐에서 빼주는 것이다. 그래야 물이 차는 속도와 맞출 수 있다. 나는 원래 절대 구글링을 하거나 힌트도 보지 않고 풀지만 이 문제는 조금 어려운 것 같아서 푸는 방법을 혼자 생각해 낸 것이 특히 더 뿌듯했다. 물이 차는 것은 딱히 BFS나 DFS로 풀지 않고 그냥 매 시점 물이 찬 곳과 인접한 동서남북을 물로 채워주었다. 다음에 찰 예정인 곳은 콤마(,)로 표시해놓고 고슴도치가 이동한 후에 별(*)로 표시해주었다.

4ms로 통과했다.

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

int dr[] = { 0, 0, -1, 1 };
int dc[] = { 1, -1, 0, 0 };

int main() {
	cin.tie(NULL);
	ios_base::sync_with_stdio(false);
	int n, m;
	cin >> n >> m;
	pair<int, int> waterLocation;
	pair<int, int> sLocation;
	vector<vector<char>> v(n, vector<char>(m));
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++) {
			cin >> v[i][j];
			if (v[i][j] == '*')
				waterLocation = make_pair(i, j);
			if (v[i][j] == 'S')
				sLocation = make_pair(i, j);
		}
	}

	int minLength = -1;
	queue<tuple<int, int, int, int>> q;
	q.push(make_tuple(sLocation.first, sLocation.second, 0, 0));
	vector<vector<bool>> visited(n, vector<bool>(m, false));

	int cnt = 1;
	bool arrivedFlag = false;
	while (!q.empty()) {
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < m; j++) {
				if (v[i][j] == '*') {
					for (int k = 0; k < 4; k++) {
						int row = i + dr[k];
						int col = j + dc[k];
						if (row >= n || col >= m || row < 0 || col < 0 || v[row][col] != '.')
							continue;
						v[row][col] = ',';
					}
				}
			}
		}
		while (!q.empty()) {
			tuple<int, int, int, int> cur = q.front();
			if (get<3>(cur) != cnt - 1)
				break;
			q.pop();
			if (v[get<0>(cur)][get<1>(cur)] == 'D') {
				minLength = get<2>(cur);
				break;
			}
			if (!visited[get<0>(cur)][get<1>(cur)]) {
				visited[get<0>(cur)][get<1>(cur)] = true;
				for (int i = 0; i < 4; i++) {
					int row = get<0>(cur) + dr[i];
					int col = get<1>(cur) + dc[i];
					if (row >= n || col >= m || row < 0 || col < 0 || !(v[row][col] == '.' || v[row][col] == 'D'))
						continue;
					if (v[row][col] == 'D') {
						arrivedFlag = true;
						minLength = get<2>(cur) + 1;
						break;
					}
					q.push(make_tuple(row, col, get<2>(cur) + 1, cnt));
				}
			}
			if (arrivedFlag)
				break;
		}
		if (arrivedFlag)
			break;
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < m; j++) {
				if (v[i][j] == ',') {
					v[i][j] = '*';
				}
			}
		}
		cnt++;
	}
	if (minLength == -1)
		cout << "KAKTUS";
	else
		cout << minLength;
	return 0;
}
728x90

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

[백준] 10799번 쇠막대기  (0) 2021.01.02
[백준] 5582번 공통 부분 문자열  (0) 2020.09.10
[백준] 13904번 과제  (0) 2020.09.02
[백준] 1038번 감소하는 수  (0) 2020.09.01
[백준] 2023번 신기한 소수  (0) 2020.09.01
728x90

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

 

13904번: 과제

예제에서 다섯 번째, 네 번째, 두 번째, 첫 번째, 일곱 번째 과제 순으로 수행하고, 세 번째, 여섯 번째 과제를 포기하면 185점을 얻을 수 있다.

www.acmicpc.net

가장 마지막날부터 첫째날까지 거꾸로 계산해야 한다는 것은 문제를 보자마자 느꼈다. 처음에는 동적 계획법으로 풀어야 하나? 싶었는데 생각보다 쉽게 풀 수 있었다.

예를 들어 입력이

7
4 60
4 40
1 20
2 50
3 30
4 10
6 5

이렇게 들어온다면

6일째에는 6 이상인 것이 5밖에 없으니 5

5일째에는 5 이상인 아직 하지 않은 과제가 없으므로 과제를 할 수 X

4일째에는 4 이상인 아직 하지 않은 과제들 중에서 최댓값인 60을 선택

3일째에는 3 이상인 아직 하지 않은 과제들 중에서 최댓값인 40을 선택

2일째에는 2 이상인 아직 하지 않은 과제들 중에서 최댓값인 50을 선택

1일째에는 1 이상이 아직 하지 않은 과제들 중에서 최댓값인 30을 선택

따라서 5 + 60 + 40 + 50 + 30 = 185가 되는 것이다.

이런 식으로 풀면 된다. 주의해야 할 것은 이미 한 과제의 점수는 벡터에서 삭제해야 한다는 것이다.

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

int n;
vector<int> v[1001];


int main() {
	cin.tie(NULL);
	ios_base::sync_with_stdio(false);
	cin >> n;
	int day, score;
	int maxDay = 0;
	for (int i = 0; i < n; i++) {
		cin >> day >> score;
		v[day].push_back(score);
		if (day > maxDay)
			maxDay = day;
	}
	int sum = 0;
	for (int i = 1; i <= maxDay; i++) {
		sort(v[i].begin(), v[i].end());
	}
	for (int i = maxDay; i >= 1; i--) {
		int maxScore = -1;
		int maxJ;
		for (int j = i; j <= maxDay; j++) {
			//erase 꼭 하기
			if (v[j].size() != 0) {
				if (v[j][v[j].size() - 1] > maxScore) {
					maxScore = v[j][v[j].size() - 1];
					maxJ = j;
				}
			}
		}
		if (maxScore != -1) {
			sum += maxScore;
			v[maxJ].erase(v[maxJ].begin() + v[maxJ].size() - 1);
		}

	}
	cout << sum;
	system("pause");
	return 0;
}
728x90

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

[백준] 5582번 공통 부분 문자열  (0) 2020.09.10
[백준] 3055번 탈출  (0) 2020.09.04
[백준] 1038번 감소하는 수  (0) 2020.09.01
[백준] 2023번 신기한 소수  (0) 2020.09.01
[백준] 10819번 차이를 최대로  (0) 2020.08.31
728x90

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

 

1038번: 감소하는 수

음이 아닌 정수 X의 자릿수가 가장 큰 자릿수부터 작은 자릿수까지 감소한다면, 그 수를 감소하는 수라고 한다. 예를 들어, 321과 950은 감소하는 수지만, 322와 958은 아니다. N번째 감소하는 수를 ��

www.acmicpc.net

처음에는

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

int n;
set<long long> s;
long long number;


void permutation(int num, vector<int> result) {
	if (s.size() > n)
		return;
	if (num == result.size()) {
		number = 0;
		for (int i = result.size() - 1; i >= 0; i--) {
			number += (pow(10, result.size() - 1 - i) * result[i]);
		}
		s.insert(number);
		return;
	}
	for (int i = 0; i <= 9; i++) {
		result[num] = i;
		if (num > 0) {
			if (result[num] < result[num - 1])
				permutation(num + 1, result);
		}
		else
			permutation(num + 1, result);
	}
}

int main() {
	cin.tie(NULL);
	ios_base::sync_with_stdio(false);
	cin >> n;
	int i = 1;
	while (true) {
		permutation(0, vector<int>(i));
		if (s.size() > n)
			break;
		i++;
	}

	int cnt = 0;
	for (set<long long>::iterator iter = s.begin(); iter != s.end(); iter++) {
		if (cnt == n) {
			cout << *iter;
			break;
		}
		cnt++;
	}
	return 0;
}

이렇게 제출했다.

나는 나름대로 재귀를 호출하기 전에 result[num] < result[num - 1]인지 확인하고 조건에 맞을 경우에만 호출했기 때문에 가지치기를 했다고 생각했다. 하지만 시간초과가 나왔다.

 

그래서

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

int n;
set<long long> s;
long long number;


void permutation(int num, vector<int> result) {
	if (s.size() > n)
		return;
	if (num == result.size()) {
		number = 0;
		for (int i = result.size() - 1; i >= 0; i--) {
			number += (pow(10, result.size() - 1 - i) * result[i]);
		}
		s.insert(number);
		return;
	}
	for (int i = 0; i <= 9; i++) {
		result[num] = i;
		if (num > 0) {
			if (result[num] < result[num - 1] && result[num] >= result.size() - 1 - num)
				permutation(num + 1, result);
		}
		else {
			if(result[num] >= result.size() - 1)
				permutation(num + 1, result);
		}
	}
}

int main() {
	cin.tie(NULL);
	ios_base::sync_with_stdio(false);
	cin >> n;
	int i = 1;
	while (true) {
		permutation(0, vector<int>(i));
		if (s.size() > n)
			break;
		i++;
	}

	int cnt = 0;
	for (set<long long>::iterator iter = s.begin(); iter != s.end(); iter++) {
		if (cnt == n) {
			cout << *iter;
			break;
		}
		cnt++;
	}
	return 0;
}

이렇게 제출했는데 또 시간초과가 났다. 9876543210보다 큰 감소하는 수는 없는데도 계속 구했기 때문이다.

 

그래서 다시

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

int n;
set<long long> s;
long long number;


void permutation(int num, vector<int> result) {
	if (num == result.size()) {
		number = 0;
		for (int i = result.size() - 1; i >= 0; i--) {
			number += (pow(10, result.size() - 1 - i) * result[i]);
		}
		s.insert(number);
		return;
	}
	for (int i = 0; i <= 9; i++) {
		if (result.size() - num - 1 <= i && (num == 0 || (num > 0 && result[num - 1] > i))) {
			result[num] = i;
			permutation(num + 1, result);
		}
	}
}

int main() {
	cin.tie(NULL);
	ios_base::sync_with_stdio(false);
	cin >> n;
	int i = 1;
	for (int i = 1; i <= 10; i++) {
		permutation(0, vector<int>(i));
	}
	int cnt = 0;
	bool flag = false;
	for (set<long long>::iterator iter = s.begin(); iter != s.end(); iter++) {
		if (cnt == n) {
			cout << *iter;
			flag = true;
			break;
		}
		cnt++;
	}
	if (!flag)
		cout << -1;
	return 0;
}

이렇게 제출했는데 0ms로 성공했다. 9자리 감소하는 수를 구하는데 맨 앞의 숫자가 8 미만이면 이미 틀려먹은 것이다.

10자리 감소하는 수를 구하는데 맨 앞의 숫자가 9 미만이면 이미 틀려먹은 것이다. 이런 식으로 가지치기를 해주었다.

728x90

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

[백준] 3055번 탈출  (0) 2020.09.04
[백준] 13904번 과제  (0) 2020.09.02
[백준] 2023번 신기한 소수  (0) 2020.09.01
[백준] 10819번 차이를 최대로  (0) 2020.08.31
[백준] 1987번 알파벳  (0) 2020.08.30
728x90

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

 

2023번: 신기한 소수

수빈이가 세상에서 가장 좋아하는 것은 소수이고, 취미는 소수를 가지고 노는 것이다. 요즘 수빈이가 가장 관심있어 하는 소수는 7331이다. 7331은 소수인데, 신기하게도 733도 소수이고, 73도 소수�

www.acmicpc.net

문제는 어렵지 않다. 하지만 처음 두 번의 제출은 시간초과로 실패했다.

가장 처음 제출한 코드는

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

int n;
vector<int> v;
set<int> answer;
int number;


void permutation(int num, vector<int> result) {
	if (num == n) {
		bool isAllPrime = true;
		for (int i = 0; i < n; i++) {
			number = 0;
			for (int j = 0; j <= i; j++) {
				number += (result[j] * pow(10, i - j));
			}
			if (number == 1)
				isAllPrime = false;
			for (int j = 2; j <= sqrt(number); j++) {
				if (number % j == 0) {
					isAllPrime = false;
					break;
				}
			}
		}

		if (isAllPrime) {
			number = 0;
			for (int i = 0; i < n; i++) {
				number += (result[i] * pow(10, n - 1 - i));
			}
			answer.insert(number);
		}
		return;
	}
	for (int i = 1; i <= 9; i++) {
		result[num] = i;
		permutation(num + 1, result);
	}
}

int main() {
	cin.tie(NULL);
	ios_base::sync_with_stdio(false);
	cin >> n;
	v = vector<int>(n);
	permutation(0, vector<int>(n));
	for (set<int>::iterator iter = answer.begin(); iter != answer.end(); iter++) {
		cout << *iter << '\n';
	}
	return 0;
}

이거였다. 그런데 이것의 문제는 일단 모든 가능한 n자리 수를 다 구하고 그 다음에 그것이 신기한 소수인지 확인했다.

그리고 신기한 소수인지 확인할 때도 예를 들어 n이 4일 때 6666이라는 절대 신기한 소수가 될 수 없는 수라도 8가 소수인지 확인, 88아 소수인지 확인, 889이 소수인지 확인, 8888이 소수인지 확인을 해주었다.  너무나도 비효율적이라는 것을 깨달았다. 애초에 8이 소수가 아닐 때부터 얘는 신기한 소수의 대상에서 제외를 해줘야 하는데 말이다.

 

그래서 두번째 코드는 이렇게 수정하였다.

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

int n;
vector<int> v;
set<int> answer;
int number;


void permutation(int num, vector<int> result) {
	if (num == n) {
		bool isAllPrime = true;
		for (int i = 0; i < n; i++) {
			if (!isAllPrime)
				break;
			number = 0;
			for (int j = 0; j <= i; j++) {
				number += (result[j] * pow(10, i - j));
			}
			if (number == 1)
				isAllPrime = false;
			for (int j = 2; j <= sqrt(number); j++) {
				if (number % j == 0) {
					isAllPrime = false;
					break;
				}
			}
		}

		if (isAllPrime) {
			number = 0;
			for (int i = 0; i < n; i++) {
				number += (result[i] * pow(10, n - 1 - i));
			}
			answer.insert(number);
		}
		return;
	}
	for (int i = 1; i <= 9; i++) {
		result[num] = i;
		permutation(num + 1, result);
	}
}

int main() {
	cin.tie(NULL);
	ios_base::sync_with_stdio(false);
	cin >> n;
	v = vector<int>(n);
	permutation(0, vector<int>(n));
	for (set<int>::iterator iter = answer.begin(); iter != answer.end(); iter++) {
		cout << *iter << '\n';
	}
	return 0;
}

 일단 모든 가능한 n자리의 수를 다 구하는 것까지는 똑같았고 n이 4일 때 8888이면 처음 8을 확인해보고 소수가 아니면 그냥 for문을 더 이상 돌지 않고 끝내었다. 하지만 이것도 시간초과가 났다.

 

그래서 세 번째에는 애초에 신기한 소수가 될 수 없다면 재귀함수를 호출하지 않고 가지를 쳐버렸다.

이게 바로 백트래킹인데 나는 바보짓을 했다는 것을 스스로 알아내었다.

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

int n;
vector<int> v;
set<int> answer;
int number;
bool flag;

void permutation(int num, vector<int> result) {
	if (num == n) {
		number = 0;
		flag = true;
		for (int i = 0; i < n; i++) {
			number += (result[i] * pow(10, n - 1 - i));
		}
		answer.insert(number);
		return;
	}
	for (int i = 1; i <= 9; i++) {
		result[num] = i;
		number = 0;
		flag = true;
		for (int j = 0; j <= num; j++) {
			number += (result[j] * pow(10, num - j));
		}
		if (number == 1)
			flag = false;
		for (int j = 2; j <= sqrt(number); j++) {
			if (number % j == 0) {
				flag = false;
				break;
			}
		}
	
		if(flag)
			permutation(num + 1, result);
	}
}

int main() {
	cin.tie(NULL);
	ios_base::sync_with_stdio(false);
	cin >> n;
	v = vector<int>(n);
	permutation(0, vector<int>(n));
	for (set<int>::iterator iter = answer.begin(); iter != answer.end(); iter++) {
		cout << *iter << '\n';
	}
	return 0;
}

 이렇게 했더니 0ms로 통과했다.

728x90

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

[백준] 13904번 과제  (0) 2020.09.02
[백준] 1038번 감소하는 수  (0) 2020.09.01
[백준] 10819번 차이를 최대로  (0) 2020.08.31
[백준] 1987번 알파벳  (0) 2020.08.30
[백준] 15683번 감시  (0) 2020.08.30
728x90

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

 

10819번: 차이를 최대로

첫째 줄에 N (3 ≤ N ≤ 8)이 주어진다. 둘째 줄에는 배열 A에 들어있는 정수가 주어진다. 배열에 들어있는 정수는 -100보다 크거나 같고, 100보다 작거나 같다.

www.acmicpc.net

N (3 ≤ N ≤ 8)이라는 것부터가 이거는 노가다로 풀으라는 것이다. 순열로 풀었다. (백트래킹)

#include <vector>
#include <algorithm>
#include <iostream>
#include <cstdlib>

using namespace std;

int n;
vector<int> v;
vector<bool> visited;
int maxSum = 0;

void permutation(int num, vector<int> result) {
	if (n == num) {
		int sum = 0;
		for (int i = 0; i < n - 1; i++) {
			sum += (abs(result[i] - result[i + 1]));
		}
		if (sum > maxSum)
			maxSum = sum;
		return;
	}
	for (int i = 0; i < n; i++) {
		if (!visited[i]) {
			visited[i] = true;
			result[num] = v[i];
			permutation(num + 1, result);
			visited[i] = false;
		}
	}
}

int main() {
	cin.tie(NULL);
	ios_base::sync_with_stdio(false);
	cin >> n;
	v = vector<int>(n);
	visited = vector<bool>(n);
	for (int i = 0; i < n; i++) {
		cin >> v[i];
	}
	permutation(0, vector<int>(n));
	cout << maxSum;
	return 0;
}
728x90

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

[백준] 1038번 감소하는 수  (0) 2020.09.01
[백준] 2023번 신기한 소수  (0) 2020.09.01
[백준] 1987번 알파벳  (0) 2020.08.30
[백준] 15683번 감시  (0) 2020.08.30
[백준] 15686 치킨 배달  (0) 2020.08.30

+ Recent posts