Processing math: 100%
반응형

 여기서는 앞의 MDP와는 달리, 우리의 전략이 자신의 state s 뿐 아니라, 상대 플레이어들의 전략으로부터도 영향을 받는다. 여기서는 플레이어가 둘(나 agent와 상대 opp)인 제로섬 게임(내가 10,10을 잃는다는 의미에서의)을 예로 설명한다.

Game

 기본적인 접근법은 searching problem과 MDP와 유사하다. searching problem은, 현재 나의 state s 노드가 succ(s,a)들을 자식노드로 같는 식으로 트리를 만들고 그 트리를 탐사함으로써 최적의 선택(action a)를 찾는다는 것을 의미하며, MDP처럼 state s에서 취할 수 있는 actions a들이 존재한다. 단지 여기서는 state sPlayers(s)에 속해있다. 또한, MDP에서는 a를 취할 때마다 cost가 존재했다면, 여기서는 s가 end state에 도달해야 Utility(s)가 존재한다( 게임이 끝나야 내가 내가 이겼는지 졌는지 알고 그에 대한 보상을 받는다). 또한, agent와 opp가 번갈아가며 s를 결정하고 둘의 s는 서로에게 fully observable하다.

 이 강의에서 사용한 예시는 다음과 같다. A박스에는 -50과 50이, B박스에는 1과 3이, C박스에는 -5와 15가 들어있으며, agent는 A, B, C 중에서 하나를 고르며, opp는 agent가 고른 박스에 들어있는 2개의 공 중 하나를 고른다. 따라서 당연히 공에 써있는 값을 최대화하기 위한 agent의 전략은 opp의 전략에 의존할 것이다. opp가 둘 중 아무거나 고른다면 박스안의 공의 평균이 가장 높은 C박스를 고르는 것이 최선의 전략일 것이고, opp가 둘 중 낮은 값의 공을 뽑는다면 들어있는 공의 최솟값이 가장 큰 B박스를 고르는 것이 최선일 것이다. 이 강의의 목적은 이러한 전략을 모델링하고 컴퓨팅을 통해서 최적의 전략을 찾는것이다.

앞으로 사용할 예제로, 빨간 선은 agent가 파란선은 opp가 선택한다.

 이 게임에서의 Value Veval은 다음과 같다.

 Veval(s)={Utility(s),IsEnd(s)aActions(s)πagent(s,a)Veval(Succ(s,a)),Player(s) = agentaActions(s)πopp(s,a)Veval(Succ(s,a)),Player(s)=opp

 2, 3번째 조건은, 누구의 턴이냐에 따라 누구의 policy를 기반으로 V값을 계산해야 하는지 나타낸다.

Expectimax

 agent가 자신의 전략을 정할 때, 가장 기본적인 전략은 내 이득을 최대화하는 선택을 하는 것이다. 이러한 선택을 하는 노드를 max노드라 한다. 이러한 max노드에서는 가장 큰 값을 같는 자식 노드를 취한다. 즉, MDP의 예제에서처럼 가능한 모든 자식노드들에 대한 평균값을 V 값으로 취하는 것이 아닌, 최댓값을 갖는 자식 노드를 취하며, 이러한 방식에 의해 얻어진 V값을 expectimax value Vexptmax(s)라 한다. 위의 예제에서 상자를 고르면 안의 두 공 중 랜덤하게 하나가 선택된다면 Vexptmax(s)=5 가 된다(두 공 중 하나가 임의로 선택되므로 평균값이 가장 높은 상자를 취한다). Expectimax를 취하는 경우의 V 값은 다음과 같다.

 Vexptmax(s)={Utility(s),IsEnd(s)maxaActions(s)Vexptmax(Succ(s,a)),Player(s) = agentaActions(s)πopp(s,a)Vexptmax(Succ(s,a)),Player(s)=opp

  이 경우의 전략을 나타내면 아래와 같다.

πexptmax(r)=argmaxaActions(s)meanaActions(s)Veval(Succ(s,a)) (agent의 전략)

πr={minaActions(s)Veval(Succ(s,a)),Prob.=12maxaActions(s)Veval(Succ(s,a)),Prob.=12 (opp의 전략)

 즉, opp는 아무거나 뽑고, agent의 경우에는 공들의 평균값이 가장 높은 것을 고른다.

 이러한 접근의 문제점은 상대방의 전략이 πr이 아니면 제대로 대처할 수 없다는 것이다. 위의 예제를 예로 들면, 상대가 두 공 중 임의로 공을 뽑지 않고 두 공 중 값이 낮은 공만을 뽑을 경우 제대로 대처할 수 없다.

Minimax

 위의 문제를 해결하기 위한 전략이 Minimax 이다. 즉, 최악의 경우만을 상정하여 내가 취할 전략을 정하는 것이다. 위의 예제에서는 상대가 값이 낮은 공만을 뽑을거라고 생각하며 a를 취하게 되므로 공의 값들 중 낮은 값이 가장 큰 B 상자를 택하게 될 것이다Vminimax(s)=1. 이러한 경우의 V값은 아래와 같이 주어진다.

 Vminimax(s)={Utility(s),IsEnd(s)maxaActions(s)Vminimax(Succ(s,a)),Player(s) = agentminaActions(s)πopp(s,a)Vminimax(Succ(s,a)),Player(s)=opp

 즉, 상대는 최솟값만 선택하므로, 나는 최솟값이 가장 큰 상자를 선택하는 것이다. minimax에서의 전략 π는 다음과 같이 주어진다.

πmax=argmaxaActions(s)Vminimax(Succ(s,a)) (agent의 전략)

πmin=argminaActions(s)Vminimax(Succ(s,a)) (opp의 전략)

비교

 이제 agent와 opp의 전략에 따라 V가 어떻게 달라지는지 보겠다. 먼저, πopp=πr 인 경우에는

V(πexptmaxr,πr)=5,V(πmax,πr)=2 가 된다. 또한, πopp=πmin 인 경우에는, V(πexptmaxr,πmin)=5,V(πmax,πmin)=1 가 되다. 즉, agent가 opp의 전략을 제대로 알지 못하는 경우에는 손해를 볼 수 있다.   

 

Computation

 위와 같은 단발성 게임이 아닌 체스 등과 같이 상대와 내가 계속해서 Action을 취하는 경우 나의 최적의 선택을 찾기 위해서는 위와 같은 트리를 만든 후, 가장 최적의 해를 주는 branch를 찾으면 될 것이다. 하지만, 여기서 문제는 tree가 너무 커지면 모든 가능성에 대해서 탐사하는 것이 현실적으로 불가능하거나 너무 비효율적이라는 것이다. 선택지가 b개이고, 트리의 깊이가 d까지 내려갈 경우에 완전탐색을 하게 되면 시간복잡도는 O(b2d)이 된다. 여기서 해결책이 두가지가 있는데, 첫번째는 내가 게임에 대하여 잘 알고 있을 경우, 트리를 탐색하지 않고, 현 상황을 분석하여 적절한 점수를 주어 결괏값을 예측하는 것이다. 예를 들어 체스의 경우, 왕의 안전성, 가지고 있는 말의 개수, 움직일 수 있는 말의 개수 등을 이용하여 각 a에 대한 Reward를 계산하는 방법이 있다. 두번째는 tree의 필요없는 가지들을 쳐내는 것이다.

반응형
반응형

유형 : 이분탐색

문제풀이:

 모든 요소 i*j를 리스트에 넣고 정렬해서 K번째를 반환하면 시간복잡도가 O(N^2)이 되어 시간초과가 뜬다. 따라서 다른 방법을 생각해야 한다.

1. N*N행렬이라 하면, 1번째 행(1부터)의 요소는 [1, 2, ... , N]이 되고, 2번째 행의 요소는 [2*1, 2*2, ..., 2*N]이 된다. 즉, i번째 행의 요소는 [i*1, i*2, ... i*N]이 되고, i번째 행에는 어떤 값 x보다 작은 값이 x//i개 (x가 i*N보다 큰 경우에는 N개) 존재하게 된다.

2. 따라서 N*N행렬에서 x보다 작은 값은 모든 i(1~N)에 대한 x//i의 합이 된다.

3. 이 값을 check(x)라 하면, x를 1과 N^2 사이에서 이분탐색하며 check(x)가 K보다 크거나 같은 가장 작은 값을 반환한다.

Python Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
n=int(input())
k=int(input())
 
def check(mid):
    num = 0
    for i in range(1,n+1):
        num+=min(mid//i,n)
    return num
 
def binSearch(n,k):
    l,r=0,k
    mid=(l+r)//2
    while l<=r:
        mid=(l+r)//2
        num = check(mid)
        if num >= k:
            r=mid-1
        else:
            l=mid+1
    if check(mid)<k:
        mid+=1
    print(mid)            
    
binSearch(n,k)
cs

line 6의 for문이 과정2가 된다.

문제 링크

 

1300번: K번째 수

세준이는 크기가 N×N인 배열 A를 만들었다. 배열에 들어있는 수 A[i][j] = i×j 이다. 이 수를 일차원 배열 B에 넣으면 B의 크기는 N×N이 된다. B를 오름차순 정렬했을 때, B[k]를 구해보자. 배열 A와 B의 인덱스는 1부터 시작한다.

www.acmicpc.net

 

반응형

'알고리즘 > 백준' 카테고리의 다른 글

백준 2468 안전 영역  (0) 2020.03.17
백준 2467 용액  (0) 2020.03.12
백준 17214 다항 함수의 적분  (0) 2020.03.10
백준 2869 달팽이는 올라가고 싶다  (0) 2020.03.09
백준 1890 점프  (0) 2020.03.09
반응형

문제풀이

1. start를 전에 "+" 또는 "-" 연산자의 인덱스라고 하면, end는 start 이후의 첫 "+" 또는 "-" 연산자가 있는 인덱스입니다.

2. start부터 end까지의 sub string을 term 이라 하면, terms에서 x의 개수와 계수를 찾아줍니다. 계수는 맨앞에서부터 term의 length에서 x의 개수를 빼준 값까지의 term의 sub string이 됩니다. 예를들면, 6xx라 하면 len(term)은 3이고, xx는 2 이므로 term[:3-2]를 해준 후 정수로 파싱해주면 됩니다. x의 개수의 경우, 저는 collections.Counter를 사용하였습니다. 계수가 존재하지 않는 경우에는 1이 됩니다.

3. 적분한 값의 계수는 원래 계수를 x의 개수에서 1을 더해준 값으로 나누어준 값이 됩니다. 또한, 적분한 계수가 1이라면 생략해주어야합니다. 또한 뒤에 x를 하나 더 붙여주면 됩니다.

 

Python Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import collections
 
eq = input()
 
def integrate(term):
    t_dic = collections.Counter(term)
    a=term[:len(term)-t_dic["x"]]
    a = int(a) if len(a) != 0 else 1
    
    b = str(a//(t_dic["x"]+1))
    result = b + "x" * (t_dic["x"]+1if b != "1" else "x" * (t_dic["x"]+1)
    return result
 
op = ["+","-"]
if eq[0in op:
    answer = eq[0]
    start = 1
    end = 1
else :
    answer = ""
    start = 0
    end = 0
if eq[start] == "0":
    print("W")
else:
    while end < len(eq):
        if eq[end] not in op:
            end += 1
        else:
            answer += integrate(eq[start:end])
            #부호
            answer += eq[end]
            start = end + 1
            end += 1
    answer += integrate(eq[start:])+"+W"
    print(answer)
cs

line 15 : 주어진 식이 "-"로 시작하는 경우입니다.

line 30 : term으로 주어지는 eq[start:end]는 부호를 제외한 숫자와 x만으로 구성된 항입니다. 부호의 경우 line 32에서 뒤의 부호를 붙여주게 됩니다.

line 35 : 저처럼 풀 경우에는 마지막 항이 while문에서 처리되지 않으므로, 따로 처리해주어야합니다.

line 23 : 0이 입력값으로 주어지는 경우 0x+W로 반환되는 것에 대한 예외처리입니다.

문제링크

 

17214번: 다항 함수의 적분

첫째 줄에 최대 일차 일변수 다항식이 주어진다. 항의 개수는 최대 2개이고, 변수는 항상 x로 주어지며, 각 항은 공백 문자로 구분되지 않는다. 주어지는 계수는 절댓값이 10,000을 넘지 않는 0이 아닌 2의 배수이고 주어지는 상수는 절댓값이 10,000을 넘지 않는 정수이다. 차수가 같은 항은 한 번만 주어진다. 단, 계수의 절댓값이 1인 경우에는 1을 생략한다. 다항식은 차수가 큰 것부터 작아지는 순서대로 주어진다.

www.acmicpc.net

 

반응형

'알고리즘 > 백준' 카테고리의 다른 글

백준 2467 용액  (0) 2020.03.12
백준 1300 K번째 수  (0) 2020.03.11
백준 2869 달팽이는 올라가고 싶다  (0) 2020.03.09
백준 1890 점프  (0) 2020.03.09
백준 17478 재귀함수가 뭔가요?  (0) 2020.03.08
반응형

요약

 LMS 알고리즘은 가장 유명한 학습법 중 하나이며, LMS 알고리즘은 성능이 좋으면서도, 빠르고 효율적이며 코드 짜기도 쉽다. 본 포스트에서는 선형회귀만을 다룹니다.

Adpative Filter

 LMS 알고리즘은 adaptive filter라고 할 수 있으며 filtering process와 adaptive process가 합쳐져 있다. w와 i번째 샘플 x(i)로부터 예상된 결과가 y(i)라 할때, y(i)와 실제 정답 d(i)를 비교함으로써 error e(i)를 얻는 과정이 filtering process이고, e(i)로부터 w를 적절하게 수정해 나가는 과정이 adaptive process이다.

 

 어떤 이상적인 분류기의 모델로서 optimal solution w가 있다고 할때, 실제 w는 알 수가 없으므로, 우리의 목표는 가지고 있는 sample들로부터 error를 가장 작게 만드는 w를 찾는 것이다. w에 관한 error를 E라 하면, E(w)<=E(w) 일 것이며, w가 optimal solution일 조건은 E(w)=0 이다.

 ww에 가까워지도록 하는 adaptive filter는 iterative descent의 방식으로 진행된다. 즉 i번째 iteration에서의 error를 E(w(n))라 하면 E(w(n+1))<E(w(n))가 된다.

Steepest Decsent Algorithm

 말그대로 가장 가파른 곳으로 내려가는 알고리즘으로, w에 대한 에러 E(w)의 경사가 가장 가파른 곳으로 내려가는 알고리즘으로, 

 w(n+1)=w(n)η\triangledown\mathcal{E}(w)$

 w(n)=w(n+1)=w(n)=η\triangledown\mathcal{E}(w) = -\eta g(n)$

가 된다. 이러한 방식을 통해 ww에 가까워지는 이유는 다음과 같이 error를 테일러 전개 함으로써 알 수 있다.

 E(w(n+1))=E(w(n))+E(w(n))Tw(n)+O((w(n))2)E(w(n))ηgT(n)g(n)=E(w(n))ηg(n)2

 E(w(n+1))<E(w(n))

Newton's Method

 이번에는 에러 함수를 이차항까지 테일러전개를 하면 아래와 같다.

 (E(w(n)))=E(w(n+1))E(w(n))

        =E(w(n))+E(w(n))Tw(n)+122E(w(n))T(w(n))2+O((w(n))3)E(w(n))

        =gT(n)w(n)+12wT(n)H(n)w(n), H(n)은 헤세 행렬 ( H(n) = \triangledown^2 \mathcal{E}(w(n))

 즉, g(n)+H(n)w(n)=0 일때 에러의 차가 최소가 된다.

w(n+1)=w(n)H1(n)g(n)

Gauss-Newton Method

 Todo

The Least Mean Square Algorithm

 에러 함수를 다음과 같이 정의하면

 E(w)=12e2(n),

 gradient vector는 다음과 같다.

 g(n)=E(w)w=e(n)e(n)w=e(n)x(n)

 여기서 Steepest Descent를 활용하여 w를 업데이트 시키면 다음과 같다.

 w(n+1)=w(n)+ηx(n)e(n)

 

LMS 알고리즘은 environment에 대한 정보가 하나도 없어도 적용이 가능하다.

 

코드로 구현한 내용은 전에 작성한 포스트에 있습니다.

 

Lecture2 Linear classifiers, SGD

Gradient Discent 어떤 함수 f(x)가 있을 때, f(x)가 최소가 되는 x 값을 찾는 방법으로, f(x)의 gradient의 반대방향으로 x값을 변화시키는 방법이다. (gradient의 방향이 f(x)를 최대화시키는 방향..

hellya.tistory.com

 

반응형

'ML > 이론' 카테고리의 다른 글

Naive Bayes' classifier  (0) 2020.10.16
Maximum a posteriori estimation  (0) 2020.03.03
반응형

13199 치킨 먹고 싶다 문제가 안풀려서 고생하다가 이 문제의 어려운 버전이라는 글이 있어서 이 문제부터 풀어보았는데, 이 문제는 너무 쉬웠다...

문제풀이

1일차 잠들기 전 높이는 A

2일차 잠들기 전 높이는 2A-B

3일차 잠들기 전 높이는 3A-2B

즉, N일차 잠들기 전의 높이는 NA-(N-1)B이고 NA-(N-1)B>V인 N의 최솟값을 찾으면 된다.

위의 식을 N에 대하여 정리하면 

N = (V-B)/(A-B)

 

Python Code

1
2
3
4
5
6
import sys,math
 
a,b,v = map(int,sys.stdin.readline().split())
 
= (v-b)/(a-b)
print(math.ceil(n))
cs

 

문제링크

 

2869번: 달팽이는 올라가고 싶다

문제 땅 위에 달팽이가 있다. 이 달팽이는 높이가 V미터인 나무 막대를 올라갈 것이다. 달팽이는 낮에 A미터 올라갈 수 있다. 하지만, 밤에 잠을 자는 동안 B미터 미끄러진다. 또, 정상에 올라간 후에는 미끄러지지 않는다. 달팽이가 나무 막대를 모두 올라가려면, 며칠이 걸리는지 구하는 프로그램을 작성하시오. 입력 첫째 줄에 세 정수 A, B, V가 공백으로 구분되어서 주어진다. (1 ≤ B < A ≤ V ≤ 1,000,000,000) 출력 첫째 줄에 달팽

www.acmicpc.net

 

반응형

'알고리즘 > 백준' 카테고리의 다른 글

백준 1300 K번째 수  (0) 2020.03.11
백준 17214 다항 함수의 적분  (0) 2020.03.10
백준 1890 점프  (0) 2020.03.09
백준 17478 재귀함수가 뭔가요?  (0) 2020.03.08
백준 2293 동전 1  (0) 2020.03.01
반응형

유형 : dp

 

 처음에는 dfs를 이용하여 모든 경로를 탐색했으나 당연히 시간초과가 나왔다.

문제풀이

1. dp를 활용해야 하는데, dp[r][c]는 (r,c)에 올 수 있는 경우의 수이다. (r,c)에서 갈 수 있는 길이가 a라 하면, (r+a,c), (r,c+a) 두 가지 경우가 가능하다. 두 경우 가능한 경우의 dp 값에 dp[r][c]를 더해주면 된다.

2. 1의 과정을 (0,0)부터 (n-1,n-1)까지 반복한다.

 

요약

 모든 경로를 다 고려할 필요 없이, dp를 이용하여 (r,c)에서 (r',c')으로 이동한다고 하면, dp[r'][c'] += dp[r][c]를 해주면 중복되는 경로들을 다시 탐색하지 않아도 된다.

 

Python Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import sys
def solution():
    dp[0][0= 1
    for r in range(n):
        for c in range(n):
            l = maps[r][c]
            if l == 0 or dp[r][c] == 0 :
                continue
            new_r = r+l
            new_c = c+l
            if new_r < n:
                dp[new_r][c] += dp[r][c]
            if new_c < n:
                dp[r][new_c] += dp[r][c]
    print(dp[n-1][n-1])
if __name__=="__main__":
    n = int(sys.stdin.readline())
    maps = [list(map(int,sys.stdin.readline().split())) for _ in range(n)]
    dp=[[0 for i in range(n)] for j in range(n)]
    solution()
cs

line 3 : 0,0에서 시작할 것이니, dp[0][0]은 0이 아닌 1로 해주어야한다.

line 7 : (r,c)에서 갈 수 있는 경우가 0이거나 (r,c)에 도착 할 수 있는 경우의 수가 0이라면 고려할 필요가 없다.

line 12, 14 : 위에서 언급한 dp[r'][c'] += dp[r][c] 과정.

 

 길이가 N인 정사각형에 대하여 이중 포문을 도므로 시간복잡도는 O(N^2)이 된다.

문제 링크

 

1890번: 점프

문제 N×N 게임판에 수가 적혀져 있다. 이 게임의 목표는 가장 왼쪽 위 칸에서 가장 오른쪽 아래 칸으로 규칙에 맞게 점프를 해서 가는 것이다. 각 칸에 적혀있는 수는 현재 칸에서 갈 수 있는 거리를 의미한다. 반드시 오른쪽이나 아래쪽으로만 이동해야 한다. 0은 더 이상 진행을 막는 종착점이며, 항상 현재 칸에 적혀있는 수만큼 오른쪽이나 아래로 가야 한다. 한 번 점프를 할 때, 방향을 바꾸면 안 된다. 즉, 한 칸에서 오른쪽으로 점프를 하거나, 아래로

www.acmicpc.net

 

반응형

'알고리즘 > 백준' 카테고리의 다른 글

백준 17214 다항 함수의 적분  (0) 2020.03.10
백준 2869 달팽이는 올라가고 싶다  (0) 2020.03.09
백준 17478 재귀함수가 뭔가요?  (0) 2020.03.08
백준 2293 동전 1  (0) 2020.03.01
백준 1038 감소하는 수  (0) 2020.02.28
반응형

재귀함수

 함수 안에서 자기 자신을 다시 호출하는 함수로, 무한 루프에 빠지지 않기 위해서는 더이상 자기자신을 호출하지 않는 종료 조건을 잘 정해야 한다.

문제풀이

 입력받은 N만큼 자기 자신을 호출하면 되므로, 재귀함수의 파라미터로 목표 depth와 현재 depth를 준 후, 자기 자신을 호출할 때는 depth에 1을 더해서 호출한다.

 depth가 N보다 작은 경우에는 아래의 글들을 프린트하되, 각 문장 앞에 ____를 depth번 반복하여 프린트 한 후, depth에 1을 더해서 자기자신을 다시 호출한다.

 

"재귀함수가 뭔가요?"

"잘 들어보게. 옛날옛날 한 산 꼭대기에 이세상 모든 지식을 통달한 선인이 있었어.

마을 사람들은 모두 그 선인에게 수많은 질문을 했고, 모두 지혜롭게 대답해 주었지.

그의 답은 대부분 옳았다고 하네. 그런데 어느 날, 그 선인에게 한 선비가 찾아와서 물었어."

 

 반면 depth가 N일 경우에는 아래의 문장 앞에 ____를 depth번 반복하여 프린트하고, 함수 호출은 하지 않는다.

 

"재귀함수가 뭔가요?"

"재귀함수는 자기 자신을 호출하는 함수라네"

 

마지막으로, 모든 depth에서 위의 경우에는 함수 호출을 한 후, 아래 경우에는 주어진 두 줄을 프린트 한 후 앞에 ____를 depth번 반복하여 프린트 한후, 아래의 문장을 프린트한다.

 

라고 답변하였지.

 

Python Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
a="\"재귀함수가 뭔가요?\""
b="\"잘 들어보게. 옛날옛날 한 산 꼭대기에 이세상 모든 지식을 통달한 선인이 있었어."
c="마을 사람들은 모두 그 선인에게 수많은 질문을 했고, 모두 지혜롭게 대답해 주었지."
d="그의 답은 대부분 옳았다고 하네. 그런데 어느 날, 그 선인에게 한 선비가 찾아와서 물었어.\""
last_b="\"재귀함수는 자기 자신을 호출하는 함수라네\""
dap="라고 답변하였지."
bar="____"
def recur(goal, now):
    temp = bar*now
    print(temp+a)
    if now < goal:
        print(temp+b)
        print(temp+c)
        print(temp+d)
        recur(goal,now+1)
    else:
        print(temp+last_b)
    print(temp+dap)
if __name__ == "__main__":
    n = int(input())
    print("어느 한 컴퓨터공학과 학생이 유명한 교수님을 찾아가 물었다.")
    recur(n,0)
cs

 

반응형

'알고리즘 > 백준' 카테고리의 다른 글

백준 2869 달팽이는 올라가고 싶다  (0) 2020.03.09
백준 1890 점프  (0) 2020.03.09
백준 2293 동전 1  (0) 2020.03.01
백준 1038 감소하는 수  (0) 2020.02.28
백준 2157 여행  (0) 2020.02.27
반응형

문제풀이

 works의 요소들의 제곱의 합이 가장 작게 하면 되는 문제로, works 요소들에서 주어진 n만큼을 적절히 빼서 works의 요소들의 최댓값을 가장 작게 만들어주면 된다. 따라서 가장 단순한 풀이로는, works를 정렬해가며 최댓값인 요소에서 1씩 빼는 과정을 n번 반복하면 된다. 

 하지만 위와 같은 방법으로 풀게되면, 당연히 효율이 좋지 못하므로, 더 효율적인 풀이를 고려해야한다. 제 풀이는 다음과 같습니다.

 1. works를 정렬한 후, i를 1씩 늘려가며 works의 i-1번째 요소까지의 모든 요소들의 값을 같게 하는데,

 1-1. 만약 works의 0번째부터 i-1번째 요소들을 모두 i번째 요소와 같도록 만들 수 있다면 바꾼 후, 바꿔준 만큼 n에서 빼줍니다.

 1-2. 불가능하다면 1과정을 멈춘다.

 2. 1-1을 거쳐 값을 똑같이 맞춰줄 수 있었던 요소들에 대하여 남은 n을 공평하게 배분한다.

 3. 남은 값들을 앞에서부터 1씩 배분한다.

 

예시

 works = [3,5,7], n = 3인 경우를 예로 들어보면 다음과 같다.

t n works[0] works[1] works[2]
0 3 7 5 3
1 1 5 5 3
2 1 5 5 3
3 0 4 5 3

알고리즘이 동작하는 과정을 편의상 t라고 했습니다. 

t=0은 과정 1의 정렬을 하는 과정입니다.

t=1은 works의 두번째 요소(works[1])까지의 요소들의 값들이 같도록 만드는 과정입니다. works[0]을  works[1]과 같도록 만들 수 있으므로 바꾸어주고 n에서 works[0]-works[1]을 빼줍니다. i가 2 이상이라면 i*(works[i-1]-works[i])를 빼주면 됩니다. 

t=2는 과정 2인데, 0이 아닌 요소가 3개인데, n은 1이므로 이 과정은 진행되지 않지만, 이해를 돕기위해 넣었습니다.

t=3은 과정 3으로, 남아있는 n을 앞에서부터 1씩 처리하는 과정입니다.

이제 t=3에서의 요소의 값들을 제곱하여 반환하면 됩니다.

 

* 시간복잡도는 최악의 경우 for문 3번으로 끝나므로, works의 길이를 N이라 하면 O(NlonN + N)이 됩니다(정확히는 O(NlonN + 3N)).

Python Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
def solution(n, works):
    if sum(works) <=n: return 0
    works.sort(reverse=True)
    
    equal = len(works)
    for i in range(1,len(works)):
        d = works[i-1]-works[i]
        if d==0:
            continue
        elif d*i<=n:
            for j in range(i):
                works[j] = works[i]
                n-=d
        else :
            equal = i
            break
            
    # 다 똑같아졌다.
    assign = n//equal
    for i in range(equal):
        works[i] -= assign
        n-=assign
    for i in range(n):
        works[i]-=1
    return sum(x**2 for x in works)
cs

line 6의 for문이 과정 1(equal index까지 요소들의 값이 같게 됩니다.),

line 19이 n을 공평하게 처리하는 부분,

line 23이 남은 n을 1씩 앞에서부터 처리하는 부분입니다.

 

문제링크

 

코딩테스트 연습 - 야근 지수 | 프로그래머스

회사원 Demi는 가끔은 야근을 하는데요, 야근을 하면 야근 피로도가 쌓입니다. 야근 피로도는 야근을 시작한 시점에서 남은 일의 작업량을 제곱하여 더한 값입니다. Demi는 N시간 동안 야근 피로도를 최소화하도록 일할 겁니다.Demi가 1시간 동안 작업량 1만큼을 처리할 수 있다고 할 때, 퇴근까지 남은 N 시간과 각 일에 대한 작업량 works에 대해 야근 피로도를 최소화한 값을 리턴하는 함수 solution을 완성해주세요. 제한 사항 works는 길이

programmers.co.kr

 

반응형

+ Recent posts