(not done) 2021년 2학기 R입문 중간고사 풀이
무궁화 꽃이 피었습니다 풀어보기
- 1. R을 이용하여 다음을 계산하여라. (3점)
- 2. 다음을 잘 읽고 물음에 답하라. (2점)
- 3. $x=(-10,-9,-8,\dots,8,9,10)$의 각 원소에 대하여 $h(g(f(x)))$의 계산결과를 구하는 코드를 작성하라. (10점)
- 4. 아래중 옳은것은? (O / X 로 답안지를 쓰고 답의 근거가 되는 코드를 작성할것) (10점)
- 5. 다음을 읽고 물음에 답하라. (10점)
- 6. 다음 문장을 읽고 참거짓을 판단하시오. (10점)
- 7. 100개의 라커 (15점)
- 8. 무궁화 꽃이 피었습니다. (25점)
- 9. 다음을 잘 읽고 시각화 하라. (15점)
2**(-5) + 2**3
sqrt(33)
for k in 100
(풀이)
-
(c)만 풀겠습니다.
-
방법1: for문을 이용
ak <-c()
for (k in 1:100) ak[k] <- 1/(k**2 + 2*k + 1)
sum(ak)
-
방법2: 벡터의 연산을 이용한다.
k=1:100
sum(1/(k**2 + 2*k + 1) )
-
수학을 좋아하는 사람?
k=1:100
sum((k+1)^(-2))
-
제 생각에는 방법2가 좋은것 같아요. (계산효율면에서 좋고 디버깅이 편해요)
1:100
(1:100)**2
(1:100)**2 + 2*(1:100)
(1:100)**2 + 2*(1:100) +1
1 / ((1:100)**2 + 2*(1:100) +1)
sum(1 / ((1:100)**2 + 2*(1:100) +1))
(풀이)
-
그냥 예제문제
seq(-10,10,0.5)
x=seq(-10,10,0.5)
ifelse(abs(x)>5,x, ifelse(abs(x)<=2,0,5))
-
검산
cbind(x,ifelse(abs(x)>5,x, ifelse(abs(x)<=2,0,5)))
단, $f(x)$,$g(x)$, $h(x)$의 정의는 각각 아래와 같다.
- $f(x)=2x+3 $
- $g(x)=\frac{e^x}{1+e^x}$
- $h(x)=max(x,0)$
(풀이)
-
문제 의도가 좀 왜곡되었어요.. $x=(-10,-9,-8, \dots, 8,9,10)$의 각 원소에 대하여! 로 바꿔야합니다.
library(tidyverse)
f = function(x) 2*x +3
g = function(x) exp(x) / (1+exp(x))
h = function(x) max(x,0)
-10:10 %>% f %>% g %>% h
-
원래 의도는 이거였습니다.
f = function(x) 2*x +3
g = function(x) exp(x) / (1+exp(x))
h = function(x) ifelse(y>0,y,0)
-10:10 %>% f %>% g %>% h
(풀이)
sum=0
for (i in 1:10){
sum=sum+(1/2)**i
print(sum)
}
- 1에 점점 가까워짐
다음은 어느 회사의 연봉에 대한 규정이다.
(가) 입사 첫째 해 연봉은 $a$원이고, 입사 19년째 해까지의 연봉은 해마다 직전 연봉에서 8%씩 인상된다.
(나) 입사 20년째 해부터의 연봉은 입사 19년째 해 연봉의 75%로 한다.
이 회사에 입사한 사람이 28년동안 근무하여 받는 연봉의 총합은?
복도에 100개의 라커가 있다. 복도를 어떤 남자가 100개의 라커 문을 전부 연다. 그리고 나서 짝수 번호의 라커를 전부 닫는다. 그 다음에는 번호가 3의 배수인 라커를 순서대로 찾아다니며 열려 있으면 닫고, 닫혀 있으면 연다. 그 다음에는 번호가 4의 배수인 라커를 순서대로 찾아다니며 열려있으면 닫고, 닫혀있으면 연다. 이후에 5의 배수, 6의 배수 .. 인 라커를 순서대로 찾아다니며 행동을 반복한다. 이런식으로 복도를 100번 지나가면 열린 라커의 문은 몇개가 되겠는가?
(풀이1)
-
문을 모두 닫은 상태로 둔다.
x= rep(FALSE, 100)
x
-
문을 여는 함수를 만든다. (닫혀있으면 열고, 열려있으면 닫는함수)
f<- function(x) !x
- 10월7일강의 논리연산자 예제1
x %>% f
- 문이 잘 열린다.
-
2,3,4,5 ... 의 배수를 찾아서 문을 열자.
- Step1: 2,3,4,5의 배수에 해당하는 원소를 뽑는 코드를 작성한다.
- Step2: Step1에서 나온 원소에 한정하여 문을 열거나 닫는다.
-
2의 배수 구현예시
(1:100) %% 2 == 0
- 짝이면 TRUE, 홀이면 FALSE 인 벡터
x[(1:100) %% 2 == 0 ]
- 1~100까지의 라커중 짝수에 해당하는 라커만 추출
x[(1:100) %% 2 == 0 ] %>% f
- 1~100까지의 라커중 짝수에 해당하는 라커만 추출 $\to$ 그 라커들은 문을 열었음
x[(1:100) %% 2 == 0 ] <- x[(1:100) %% 2 == 0 ] %>% f
x
- 결과를 저장
-
3의 배수 구현예시
x[(1:100) %% 3 == 0 ] <- x[(1:100) %% 3 == 0 ] %>% f
-
4의 배수.. 5의 배수.. $\to$ 함수를 만들자.
g=function(x,a){
n=length(x)
x[(1:n) %% a == 0 ] <- x[(1:n) %% a == 0 ] %>% f ## 연산
x ## 결과를 리턴
}
-
검산을 해보자. (검산을 쉽게하기 위해서 10개정도의 라커만 고려하자.)
x=rep(FALSE, 10)
x
x %>% f
x %>% f %>% g(2)
x %>% f %>% g(2) %>% g(3)
-
잘 되는것 같습니다. 이제 일반화해서 답을 구해보면
x=rep(FALSE, 100) # x를 선언, FALSE의 의미는 문이 닫혀있다.
x=f(x) # 1회 복도를 지나가면서 모든 문을 열어요
for (i in 2:100){ # 2회부터 100회까지 지나가면서
x=g(x,i) # (1) 2,3,4,5 ... , 100의 배수에 해당하는 문을 선택 (2) 문이 열려있으면 닫고, 닫혀있으면 열어요
}
-
결과는 아래와 같다.
x
sum(x)
(풀이2)
x=rep(TRUE,100)
for (i in 2:100) x[(1:100) %% i ==0] = !( x[(1:100) %% i ==0] )
sum(x)
- 시험제출용 코드입니다. 공부용은 아니에요
- 차근차근 디버깅을 하고 코드를 확인해가면서 혹시 모를 실수를 방지할 수 있는 풀이 1이 좋아요.
- 코드 중간결과를 시각화해서 내가 잘 구현하고 있는지 끊임없이 확인해야 합니다.
- 그 다음에 코드를 효율적으로 정리합니다.
총 456명의 참가자가 '무궁화 꽃이 피었습니다' 게임에 참가한다. 기본적인 게임의 규칙은 아래와 같다.
-
술래는 총 10회간 벽을 보고 '무궁화 꽃이 피었습니다' 를 외친다.
-
참가자는 술래가 있는 곳 까지 이동해야 살 수 있다.
-
술래는 벽을 보고 '무궁화 꽃이 피었습니다'를 외치다가 구호가 끝남과 동시에 뒤를 돌아본다. 이때 움직이는 사람은 죽는다
따라서 참가자는 술래가 벽을 보고 '무궁화 꽃이 피었습니다'를 외치는 동안만 이동할 수 있다. 욕심을 부려 더 이동하고자 하면 죽을 수 있다. 반대로 죽는 것을 지나치게 두려워한 나머지 매턴마다 조금씩만 이동한다면 10회의 제한횟수 내에 술래에게 도달하지 못하여 죽는다.
게임환경과 관련된 세부적인 설정은 아래와 같다.
-
술래와 참가자의 거리는 35이다.
-
술래는 처음 벽을 보고 $x$초간 무궁화 꽃이 피었습니다를 외친다.
-
모든 참가자는 1초에 거리1이상 움직일 수 없다고 가정한다. (예를들어 2.4초 동안은 최대 2.4의 거리를 이동할 수 있다. 반면 이동을 원치않으면 0의 거리만큼 움직이므로 0~2.4사이의 거리를 움직일 수 있다)
술래와 참가자에 대한 설정값은 아래와 같다.
술래에 대한 설정값
-
처음에는 술래가 10초간 무궁화 꽃이 피었습니다를 외친다.
-
그 다음에는 술래가 9.5초간 무궁화 꽃이 피었습니다를 외친다.
-
그 다음에도 0.5초씩 구호를 외치는 시간을 줄인다. 이것을 10회 반복한다.
참가자에 대한 설정값
-
처음에는 참가자가 "본인의번호/100"을 계산하여 나온 숫자만큼 움직인다. 즉 10번 참가자는 0.1의 거리를 움직이고 456번 참가자는 4.56의 거리를 움직인다.
-
그 다음은 처음에 본인이 이동했던 거리에 1씩 더하여 움직인다. 즉 10번 참가자는 1.1의 거리를 움직이고 456번 참가자는 5.56의 거리를 움직인다.
-
예시1
300번 참가자의 경우 아래와 같이 이동하므로
1회 | 2회 | 3회 | 4회 | 5회 | 6회 | |
---|---|---|---|---|---|---|
술래의 외침시간 | 10 | 9.5 | 9.0 | 8.5 | 8.0 | 7.5 |
참가자의 이동폭 | 3 | 4 | 5 | 6 | 7 | 7.5 |
참가자의 총 이동거리 | 3 | 7 | 12 | 18 | 25 | 32.5 |
생존할 수 없다. (6회에서 32.5까지 이동후 사망)
-
예시2
350번 참가자의 경우 아래와 같이 이동하므로
1회 | 2회 | 3회 | 4회 | 5회 | 6회 | |
---|---|---|---|---|---|---|
술래의 외침시간 | 10 | 9.5 | 9.0 | 8.5 | 8.0 | 7.5 |
참가자의 이동폭 | 3.5 | 4.5 | 5.5 | 6.5 | 7.5 | 7.5 |
참가자의 총 이동거리 | 3.5 | 8 | 13.5 | 20 | 27.5 | 35 |
생존 할 수 있다. (6회에서 정확하게 7.5초간 이동하고 살아남는다)
-
예시3
400번 참가자의 경우 아래와 같이 이동하므로
1회 | 2회 | 3회 | 4회 | 5회 | 6회 | |
---|---|---|---|---|---|---|
술래의 외침시간 | 10 | 9.5 | 9.0 | 8.5 | 8.0 | 7.5 |
참가자의 이동폭 | 4 | 5 | 6 | 7 | 8 | 5 |
참가자의 총 이동거리 | 4 | 9 | 15 | 22 | 30 | 35 |
생존 할 수 있다. (6회에서 5초간만 이동하면 35만큼 이동하므로 살아남는다)
b <- 1/100
c <- 0
for(i in 1:10){
a <- 10 - 0.5 * i
c <- c + b
if(c>=35|a<=b){
print("탈락")
break
}
b <- b + 1
if(a<=b){
b <- a
if(c >= 35){
b <- 35 - c
}
}}
1회 | 2회 | 3회 | 4회 | 5회 | 6회 | 7회 | 8회 | |
---|---|---|---|---|---|---|---|---|
술래의 외침시간 | 10 | 9.5 | 9.0 | 8.5 | 8.0 | 7.5 | 7 | 6.5 |
참가자의 이동폭 | 0.01 | 1.01 | 2.01 | 3.01 | 4.01 | 5.01 | 6.01 | 6.5 |
참가자의 총 이동거리 | 0.01 | 1.02 | 3.02 | 6.03 | 10.04 | 15.05 | 21.06 | 27.56 |
b <- 67/100
c <- 0
for(i in 1:10){
a <- 10 - 0.5 * i
c <- c + b
if(c>=35|a<=b){
print("탈락")
break
}
b <- b + 1
if(a<=b){
b <- a
if(c >= 35){
b <- 35 - c
}
}}
1회 | 2회 | 3회 | 4회 | 5회 | 6회 | 7회 | 8회 | 9회 | |
---|---|---|---|---|---|---|---|---|---|
술래의 외침시간 | 10 | 9.5 | 9.0 | 8.5 | 8.0 | 7.5 | 7 | 6.5 | 6 |
참가자의 이동폭 | 0.67 | 1.67 | 2.67 | 3.67 | 4.67 | 5.67 | 6.67 | 6.5 | 2.81 |
참가자의 총 이동거리 | 0.67 | 2.34 | 5.01 | 8.68 | 13.35 | 19.02 | 25.69 | 32.19 | 35 |
b <- 218/100
c <- 0
for(i in 1:10){
a <- 10 - 0.5 * i
if(c<35){
c <- c + b
}
if(c>=35|a<=b){
print("탈락")
break
}
b <- b + 1
if(a<=b){
b <- a
if(c >= 35){
b <- 35 - c
}
}}
1회 | 2회 | 3회 | 4회 | 5회 | 6회 | 7회 | |
---|---|---|---|---|---|---|---|
술래의 외침시간 | 10 | 9.5 | 9.0 | 8.5 | 8.0 | 7.5 | 7 |
참가자의 이동폭 | 2.18 | 3.18 | 4.18 | 5.18 | 6.18 | 7.18 | 6.92 |
참가자의 총 이동거리 | 2.18 | 5.36 | 9.54 | 14.72 | 20.90 | 28.08 | 35 |
b <- 456/100
c <- 0
for(i in 1:10){
a <- 10 - 0.5 * i
c <- c + b
if(c>=35&a<=b){
print("생존")
break
}
b <- b + 1
if(a<=b){
b <- a
if(c >= 35){
b <- 35 - c
}
}}
1회 | 2회 | 3회 | 4회 | 5회 | 6회 | |
---|---|---|---|---|---|---|
술래의 외침시간 | 10 | 9.5 | 9.0 | 8.5 | 8.0 | 7.5 |
참가자의 이동폭 | 4.56 | 5.56 | 6.56 | 7.56 | 8 | 2.76 |
참가자의 총 이동거리 | 4.56 | 10.12 | 16.68 | 24.24 | 32.24 | 35 |
(풀이)
-
전략: 각 플레이어별로 죽느냐 사느냐를 판단하는 로직을 구현하고 for문을 돌리면 된다.
-
죽느냐 사느냐를 판단하는 방법: 살아있는 동안 이동한 총거리 >= 35
-
살아있는 동안 이동한 총거리를 계산하는 방법:
- 죽을위험이 없는 횟수에서 이동한 총거리 + 죽을위험이 있는 횟수에서 술래의 외침시간 동안 이동한 거리
a = 10-0.5*(0:9)
a
b = 400/100 + (0:9)
b
a>=b
which(a<b)[1]
sum(b[a>=b]) + a[which(a<b)[1]]
(sum(b[a>=b]) + a[which(a<b)[1]])>=35
if((sum(b[a>=b]) + a[which(a<b)[1]]>=35)){print("생존")}
num <- 0
for(i in 1:456){
a = 10-0.5*(0:9)
b = i/100 + (0:9)
if((sum(b[a>=b]) + a[which(a<b)[1]]>=35)){
num <- num + 1
} }
print(num)
-
죽을위험이 없는 횟수에서 이동한 총거리
num=350
x= seq(10,5.5,by=-.5) ## 술래의 외침시간
steps = num/100 + 0:9 ## 참가자가 이동하려는 거리
x>=steps
sum(steps[x>=steps])
-
죽을 위험이 있는 횟수에서 이동한 거리
x[x<steps][1]
-
더하면?
sum(steps[x>=steps]) + x[x<steps][1] ## 총이동거리
-
총이동거리 >= 35 이면 살아남을 수 있음
sum(steps[x>=steps]) + x[x<steps][1] >= 35
-
정리하면
x=seq(10,5.5,by= -0.5)
surv<-c()
for (num in 1:456){
steps = num/100 + 0:9
surv[num] <- sum(steps[x>=steps]) + x[x<steps][1] >= 35
}
sum(surv)
다음은 인터넷에서 어떠한 자료를 다운받아 매트릭스로 저장하는 코드이다.
df=read.csv("https://raw.githubusercontent.com/miruetoto/yechan/master/_notebooks/round2.csv")
mat=as.matrix(df)
매트릭스는 mat
이라는 변수에 저장되어 있다.
df=read.csv("https://raw.githubusercontent.com/miruetoto/yechan/master/_notebooks/round2.csv")
mat=as.matrix(df)
plot(mat[,1],mat[,2])
plot(mat)
- R은 알아서 해석해서 해주는 것이 좀 많아요..
- 이것은 프로그램 만든 사람이 편의성을 위해 "만들어준" 기능입니다.
- 이러한 기능을 이용한 풀이는 좋은 풀이가 아닌데 그 이유는 프로그램을 만든 사람의 마음에 따라서 시각화가 가능하기도 하고 불가능하기도 합니다.
mat[1,]
f = function(X){
dim(X)=c(2,1)
X
}
rbind(c(0,-1),c(-1,0)) %*% f(mat[1,])
g = function(X){
dim(X)=c(1,2)
X
}
dim(mat2)
mat2 = mat*0
for (i in 1:5513) mat2[i,] = rbind(c(0,-1),c(-1,0)) %*% f(mat[i,]) %>% g
plot(mat2[,1],mat2[,2],col='red')
(풀이)
-
사실 아래는 같음
rbind(c(0,-1),c(-1,0)) %*% c(12,312) ## c(12,313) 벡터
rbind(c(0,-1),c(-1,0)) %*% matrix(c(12,312),nrow=2)
-
그리고 아래도 같음
c(12,313) %*% rbind(c(0,-1),c(-1,0))
matrix(c(12,313),nrow=1) %*% rbind(c(0,-1),c(-1,0))
-
c(12,313)이 때로는 벡터로, 때로는 $n\times 1$인 매트릭스로 생각할 수 있고, 때로는 $1\times n$ 매트릭스로 해석할 수도 있음.
-
따라서 아래와 같이 풀어도 가능함.
mat2 = mat*0
for (i in 1:5513) mat2[i,] = rbind(c(0,-1),c(-1,0)) %*% mat[i,]
plot(mat2,col='red')
(풀이3)
-
매트릭스의 곱셈을 잘 이해했다면?
head(mat)
rbind(c(0,-1),c(-1,0)) %*% c(12,313)
rbind(c(0,-1),c(-1,0)) %*% c(12,314)
cbind(c(12,313),c(12,314))
rbind(c(0,-1),c(-1,0)) %*% cbind(c(12,313),c(12,314))
-
응용하면
rbind(c(0,-1),c(-1,0)) %*% t(mat) %>% t %>% plot(col='red')
-
매트릭스 A,B의 곱에서 뒷부분을 임의의 칼럼으로 쪼개서 각각 연산한뒤 합쳐도 성립한다.
-
매트릭스 A,B의 곱에서 앞부분을 임의의 로우로 쪼개서 각각 연산한뒤 합쳐도 성립한다.