- 두 자릿수 입력만 받는다면 O(1)이겠지만, 3자릿수가 넘어가면 각각의 수에 대해 확인해야하므로 O(N)
1) 각 자릿수의 차를 직접 구해보기
- 세 번째 자릿수 - 두 번째 자릿수 == 두 번째 자릿수 - 첫 번째 자릿수
소스코드
#include<iostream>
using namespace std;
int n, cnt = 0;
int main(void){
cin >> n;
for (int i = 1; i <= n; i++){
if (i < 100)
cnt++;
else {
int f = i % 10;
int s = (i / 10) % 10;
int t = i / 100;
if ((f - s) == (s - t))
cnt++;
}
}
cout << cnt << "\n";
return 0;
}
2) 등차수열의 특징을 활용
- 사실 특징이라고 할게 있나...
- a, a+d, a+2d ... 이므로 a + a+2d = (a+d) * 2
소스코드
else {
int f = i % 10;
int s = (i / 10) % 10;
int t = i / 100;
if (f+t == 2*s)
cnt++;
}
[출처 : BOJ, 문제에 대한 모든 권리는 BOJ(acmicpc.net, startlink)에 있음]
: 시간복잡도 : 첫 짝이 없는 친구를 고르는 경우(1)(0 학생이 무조건 처음이므로) * 0학생과 친구인 관계(N-1) * 0과 0 친구를 제외한 다음 짝이 없는 친구를 고르는 경우(N-2) * 두 번째 고른 학생과 친구인 관계(N-3) * ... * 1 = 9! ≒ 360,000
즉, 1억번 내에 들어옴
: 공간복잡도 : global variable - int * 3 = 12byte
local variable - bool * 100 + bool * 10 = 110byte
≒ 122byte
즉, 2^16kb 이내
5, 6) 계획 수행하기 및 회고하기
실패한 소스코드
- 중복처리를 안해줌
- 해당 코드에서는 (0, 1) (2, 3) 과 (2, 3) (0, 1) 이 다른 경우로 판단함.
#define LOCAL_TEST
#include<iostream>
using namespace std;
int n, m, cnt;
// isfriend : 두 명이 친구인지 여부
// check : 친구랑 짝이 지어졌는지 여부
// remain : 짝지을 학생이 몇명 남아있는지 여부
void dfs(bool isfriend[][10], bool check[10], int remain){
// 짝지을 학생이 없으면 하나의 경우를 찾았으므로 cnt++
if (remain == 0){
cnt++;
return;
}
// 짝을 지을 첫번째 학생 선택
for (int i = 0; i < n; i++){
if (!check[i]){
// i 번째 학생과 친구인 학생
for (int j = 0; j < n; j++){
// i와 j가 친구이고 j가 다른 친구와 짝짓지 않은 경우, 친구임을 check 배열에 없데이트하고 재귀
if (isfriend[i][j] && !check[j]){
check[i] = check[j] = true;
dfs(isfriend, check, remain - 2);
check[i] = check[j] = false;
}
}
}
}
return;
}
int main(void){
#ifdef LOCAL_TEST
freopen("input.txt", "r", stdin);
#endif
int T;
cin >> T;
while (T--){
n = m = cnt = 0;
cin >> n >> m;
bool isfriend[10][10] = { false };
bool check[10] = { false };
for (int i = 0; i < m; i++){
int a, b;
cin >> a >> b;
isfriend[a][b] = true;
}
dfs(isfriend, check, n);
cout << cnt << "\n";
}
#ifdef LOCAL_TEST
fclose(stdin);
#endif
return 0;
}
성공한 소스코드
- 중복처리는 시작점을 고정하는게 제일 좋음
- 단, 이 방법은 a와 b가 친구이면 isfriend[a][b] = isfriend[b][a] = true로 해줘야 (1,2) (3,0) 같은 경우를 골라낼 수 있음
- 아니면 0과 3이 친구가 아니므로 경우의 수가 빠지게 됨
※ 시간복잡도 : 학생 하나 고르는데 걸리는 시간(1) * 고른 학생과 친구인 학생 고르는데 걸리는 시간(N-1) * 두명을 제외한 학생 한명과 그 친구를 고르는데 걸리는 시간(N-3) * ... * 1= 9 * 7 * 5 * 3 * 1 = 945
공간복잡도 : 위 공간복잡도 + 각 재귀마다 int student가 추가됨(int * (9 * 7 * 5 * 3 * 1) = 3780byte
즉, 3920byte
#define LOCAL_TEST
#include<iostream>
using namespace std;
int n, m, cnt;
// isfriend : 두 명이 친구인지 여부
// check : 친구랑 짝이 지어졌는지 여부
// remain : 짝지을 학생이 몇명 남아있는지 여부
void dfs(bool isfriend[][10], bool check[10], int remain){
// 짝지을 학생이 없으면 하나의 경우를 찾았으므로 cnt++
if (remain == 0){
cnt++;
return;
}
// 짝을 지을 첫번째 고정학생 선택
int student = 0;
for (int i = 0; i < n; i++){
if (!check[i]){
student = i;
break;
}
}
// student 학생과 친구인 학생
for (int j = 0; j < n; j++){
// student와 j가 친구이고 j가 다른 친구와 짝짓지 않은 경우, 친구임을 check 배열에 없데이트하고 재귀
if (isfriend[student][j] && !check[j]){
check[student] = check[j] = true;
dfs(isfriend, check, remain - 2);
check[student] = check[j] = false;
}
}
return;
}
int main(void){
#ifdef LOCAL_TEST
freopen("input.txt", "r", stdin);
#endif
int T;
cin >> T;
while (T--){
n = m = cnt = 0;
cin >> n >> m;
bool isfriend[10][10] = { false };
bool check[10] = { false };
for (int i = 0; i < m; i++){
int a, b;
cin >> a >> b;
isfriend[a][b] = isfriend[b][a] = true;
}
dfs(isfriend, check, n);
cout << cnt << "\n";
}
#ifdef LOCAL_TEST
fclose(stdin);
#endif
return 0;
}
※ 왜 종만북의 코드와 속도는 동일하지만 종만북 코드로 제출한 사람들의 코드는 0ms도 있음