Computational Thinking
Computational Thinking
명제 논리
역, 이, 대우
조건문 $p→q$ 에 대하여
- 역(converse) : $q→p$
- 이(inverse) : $\sim p→ \sim q$
- 대우(contrapositive) : $\sim q→ \sim ~p$ (조건문이 참이면 대우도 참이다)
진리표(p→q)
p | q | p→q |
---|---|---|
T | T | T |
T | F | F |
F | T | T |
F | F | T |
T는 참, F는 거짓.
p가 F일 때, p→q가 항상 T인 이유는 거짓을 증명할 수 없으면 항상 참이기 때문이다. 전제가 거짓이므로 결과는 참인지 거짓인지 증명할 수 없다. 증명할 수 없기 때문에 항상 참이다.
귀류법
귀류법이란 어떤 명제가 틀렸다고 가정한 후, 추론했을 때, 모순이 발생함을 이끌어내어 가정이 거짓임을 증명하는 방법이다.
- 반례를 들어 증명하면 된다.
- 예를 들어, ‘$\sqrt2$는 무리수이다’를 증명한다고 했을 때 $\sqrt2$를 유리수라고 생각하여 $ \frac{a}{b} $ (a와 b는 서로소)라고 가정하여 푼 후, 이것이 모순이라는 걸 증명하면 된다.
- 서로소 : 여러 개의 수들 사이에서 1이외의 공약수가 없는 것
귀납법
수학적 귀납법의 기본형 : $P(1)$이 참이고, $P(n) \rightarrow P(n+1)$이 참이면 $P(n)$은 모든 자연수 n에 대해서 참이다.
- 증명할 때는 $P(n+1)$에서 $P(n)$을 찾아서 대입해 증명하면 된다
항진 명제 - 항상, 모두 참인 명제
모순 명제 - 항상, 모두 거짓인 명제
함수
역함수
치역이 곧 정의역이 되고, 치역이 곧 정의역이 되는 것. 일대일 함수(전단사함수)일 때만 역함수가 가능하다.
단사함수 = 일대일함수
전사함수 = 다대일함수
점화식
수학에서는 어떤 수열의 각각의 항들의 관계를 나타낸 식이지만 알고리즘에서는 어떤 함수를 자신보다 더 작은 변수에 대한 함수와의 관계로 표현한 것으로 본다
점화식은 프로그래밍에서 재귀함수로 만들 수 있기 때문에 중요하다.
Ex) $f(n) = n*f(n-1)$
수열 공식
등차 수열의 일반항 : $a_n = a_1 + (n-1)*d$
등차 수열의 합 : $S_n = {n(2a + (n-1) *d) \over 2}$
- 가우스의 합 방식과 같이 생각하면 구할 수 있다.
등비 수열의 일반항 : $a_n = a_1*r^{n-1}$
등비 수열의 합 : $S_n = {a(r^n-1) \over r-1}$
- $S_n$에 $rS_n$을 빼주는 형식으로 구할 수 있다.
계차수열 : $a_n = a_1+ {\sum _{k=1} ^{n-1} b_k}$
순열
- 서로 다른 n개의 원소에서 r개를 중복없이 골라 순서에 상관있게 일렬로 나열하는 것을 n개에서 r개를 선택하는 순열이라고 한다.
${n}\mathrm{P}{r} = \frac{n!}{(n-r)!}$, ${n}\mathrm{P}{r} = {n}\mathrm{C}{r} * r!$
- 중복이 없는 순열 코드
- N개 중에서 M개를 순서와 상관있으면서 중복없이 뽑는다.
- 중복이 없을 때는 체크를 따로 해줘야 한다.
public static void permutation(int depth, int[] resArr, boolean[] arrCheck) {
// M개를 뽑는다.
if(depth == M) {
for(int res : resArr) {
System.out.print(res + " ");
}
System.out.println();
return;
}
// N개 중에서
for(int i = 1 ; i <= N ; i++) {
if(arrCheck[i]) continue;
arrCheck[i] = true;
resArr[depth] = i;
permutation(depth+1, resArr, arrCheck);
arrCheck[i] = false;
}
}
조합
서로 다른 n개의 원소에서 순서에 상관없이 r개를 뽑을 때, n개에서 r개를 택하는 조합이라고 한다.
${n}\mathrm{C}{r}$ 또는 ${n \choose r}$ 로 쓰며, ${n}\mathrm{C}{r} = \frac{{n}\mathrm{P}{r}}{r!} = \frac{n!}{(n-r)!r!}$
- ${n}\mathrm{C}{1} = n$
- ${n}\mathrm{C}{n} = 1$
- ${n-1}\mathrm{C}{r-1} = {n}\mathrm{C}{r} * {r \over n}$
- ${n}\mathrm{C}{r} = {n-1}\mathrm{C}{r-1} + {n-1}\mathrm{C}{r}$
- ${n}\mathrm{C}{r} = {n}\mathrm{C}{n-r}$
- 3개 중 1개를 뽑는 경우나, 3개 중 2개를 뽑는 경우는 같다.
- $(x+y)^2$의 각각의 계수를 구할 때 곱해보지 않고 조합으로 풀 수 있다.
- $x$와 $y$가 들어있는 바구니가 2개 있다고 생각한다. 여기서 뽑는 경우의 수를 구할 때, $xx$, $xy$, $xy$, $yy$의 경우가 있고 $xx$, $xy$, $yy$가 나올 수 있다.
- $x$ 또는 $y$ 중에 아무거나 선택해서 그 문자(예를 들어, $x$)가 나올 수 있는 경우는 ${2}\mathrm{C}{0}$, ${2}\mathrm{C}{1}, $${2}\mathrm{C}{2}$와 같다. 바로 계수가 된다.
- 그리고 그것을 다 더할 시, $x^2 + 2xy + y^2$가 된다.
- 위와 같은 이유로 $(x+y)^1$, $(x+y)^2$, $(x+y)^3$, …$(x+y)^n$의 값들은 $\sum_{k=0}^n {n}\mathrm{C}_k x^{n-k}*y^k$ 가 된다. $x$와$y$에 1을 대입하면 $2^n = \sum{k=0}^n {_n}\mathrm{C}_k$ 가 나오게 된다.
- 이는 원소 n개인 집합의 부분 집합의 수와 같다. 원소를 한 개, 두 개, 세 개..뽑는 것으로 ${}_n\mathrm{C}_0 + {}_n\mathrm{C}_1 + … {}_n\mathrm{C}_n$ 과 같다.
- 파스칼의 삼각형에서 n일 때 그 행의 합을 구하는 것과 같다.
- 중복이 없는 조합 코드
- N개 중에서 M개를 순서와 상관없으면서 중복없이 뽑는다.
- 오름차순으로 정렬되어있는 배열이라면 훨씬 쉽게 코드를 짤 수 있다.
- 처음 시작을 0또는 1같이 맨 처음으로 하고 현재 있는 숫자보다 계속해서 더 크면 되므로 작거나 같을 때 continue시켜주면 된다.
- 대신 계속 커져야하는 것을 보장받아야하기 때문에 해쉬처럼 N의 범위보다 큰 값을 정해야한다.
- 이러면 순열과 같이 체크배열을 따로 안 만들어줘도 돼서 좋다.
- 그리고 이 방법은 for문 하나가 아니라 for문이 두 개라도 조건에
r * 1000 + c
으로 만들어줄 수 있기때문에 더 범용성이 높다.
public static void combination(int depth, int[] resArr, int limit) {
if(depth == M) {
for(int res : resArr) {
System.out.print(res + " ");
}
System.out.println();
return;
}
for(int i = 1 ; i <= N ; i++) {
// 해쉬처럼 일부러 크게 만들어서 다음 것보다 작은, 유일한 값을 만든다.
if(i * 100 <= limit) continue;
resArr[depth] = i;
combination(depth+1, resArr, i * 100);
}
}
중복순열
서로 다른 n개의 원소에서 r개를 중복이 가능하도록 골라 순서에 상관있게 일렬로 나열하는 것을 n개에서 r개를 선택하는 중복순열이라고 한다.
${n}\mathrm{\pi}{k} = n^k$
- 중복이 있는 순열 코드
- N개 중에서 M개를 순서와 상관 있으면서 중복있이 뽑는다.
public static void permutation(int depth, int[] resArr) {
if(depth == M) {
for(int res : resArr) {
System.out.print(res + " ");
}
System.out.println();
return;
}
// N개 중에서
for(int i = 1 ; i <= N ; i++) {
resArr[depth] = i;
permutation(depth+1, resArr);
}
}
중복조합
주어진 집합의 원소 중에서 뽑되 동일한 원소의 중복을 허용하여 뽑아내는 것
- Ex) 1과 2에서 세 개를 취하는 중복조합은 111, 112, 122, 222가 있다.
-
${n}\mathrm{H}{r} = {n+r-1}\mathrm{C}{r}$
- 중복이 있는 조합 코드
- N개 중에서 M개를 순서와 상관 없으면서 중복있이 뽑는다.
- 중복이 있게 하려면 큰 대신 같은 값일 때도 허락해주도록 하면된다. 작거나 같음이 아니라 작을 때만 continue 시켜준다.
public static void combination(int depth, int[] resArr, int limit) {
if(depth == M) {
for(int res : resArr) {
System.out.print(res + " ");
}
System.out.println();
return;
}
for(int i = 1 ; i <= N ; i++) {
// 해쉬처럼 일부러 크게 만들어서 다음 것보다 작은, 유일한 값을 만든다.
if(i * 100 < limit) continue;
resArr[depth] = i;
combination(depth+1, resArr, i * 100);
}
}
증명하는 방법
- 자연수 n에 대하여~ 를 증명할 때는 가능한 경우의 수를 모두 구해서 증명하면된다.
- n이 홀수일 때와 짝수일 때
- 3k, 3k+1, 3k+2 등…
- 대우를 통해서 증명하는 방법을 써도 되고, 홀수는 2k+1, 짝수는 2k로 잡는다.
- 나누어 떨어지는 것은 수로 나타낸다. Ex) 3이면 3k, 3k+1, 3k+2
- 무리수 임을 증명할 때 귀류법으로 유리수라고 생각해 a/b로 표현해서 제곱하는 방식으로 풀면 된다.