문제:

<그림1>과 같이 정사각형 모양의 지도가 있다. 1은 집이 있는 곳을, 0은 집이 없는 곳을 나타낸다. 철수는 이 지도를 가지고 연결된 집들의 모임인 단지를 정의하고, 단지에 번호를 붙이려 한다. 여기서 연결되었다는 것은 어떤 집이 좌우, 혹은 아래위로 다른 집이 있는 경우를 말한다. 대각선상에 집이 있는 경우는 연결된 것이 아니다. <그림2>는 <그림1>을 단지별로 번호를 붙인 것이다. 지도를 입력하여 단지수를 출력하고, 각 단지에 속하는 집의 수를 오름차순으로 정렬하여 출력하는 프로그램을 작성하시오.

입력:

첫 번째 줄에는 지도의 크기 N(정사각형이므로 가로와 세로의 크기는 같으며 5<=N<=25)이 입력되고, 그 다음 N줄에는 각각 N개의 자료(0 혹은 1)가 입력된다.

출력:

첫 번째 줄에는 총 단지수를 출력하시오. 그리고 각 단지내 집의 수를 오름차순으로 정렬하여 한 줄에 하나씩 출력하시오.

풀이방법:

 이 문제는 크게 두 부분으로 나누어서 풀어야 한다. check에 <그림2>와 같이 배열을 만드는 부분, 그리고 <그림2>를 탐색하며 각 단지번호의 갯수를 세는 부분으로 나누어서 풀었다.

 첫 부분은 dfs를 사용해서 값을 할당했다. <그림1>의 배열을 탐색하면서 값이 1이고 check가 아직 0인(방문을 하지 않은) 값을 만나면 그 값으로부터 dfs를 시작하도록 한다. check에 count 값을 할당하면서 다음 dfs 값으로 이동하였다. 이 때 상하좌우로 이동할 수 있었는데 깔끔하게 이동할 수 있도록 dx와 dy라는 배열을 만들어서 하나의 반복문으로 이동을 간단하게 만들었다.

 이렇게 한 단지를 다 탐색하고 나면 다시 처음상태로 돌아가서 다시 값이 1이고 check가 0인 곳을 찾고, 위와 동일하게 check에 count에 1이 증가한 값들을 할당해주면 된다.

 <그림1>을 모두 탐색하고 난다면 check에 <그림2>와 같이 지도를 얻을 수 있다. 그러면 이 check를 count의 갯수만큼 탐색하며 단지번호의 갯수를 세도록 한다.

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
def dfs(x,y,count):
    check[x][y]=count
    for i in range(4):
        newX=x+dx[i]
        newY=y+dy[i]
        if (0<= newX < n and 0<=newY <n):
            if house[newX][newY]==1 and check[newX][newY]==0:
                dfs(newX,newY,count)
 
dx=[0,0,1,-1]
dy=[1,-1,0,0]
n=int(input())
house=[]
for i in range(n):
    house.append(list(map(int,list(input()))))
check=[[0 for i in range(n)]for j in range(n)]
count=0
for i in range(n):
    for j in range(n):
        if house[i][j]==1 and check[i][j]==0:
            count+=1
            dfs(i,j,count)
print(count)
cnt=0
answers=[]
for i in range(count):
    cnt+=1
    answer=0
    for j in range(n):
        for k in range(n):
            if check[j][k]==cnt:
                answer+=1
    answers.append(answer)
answers.sort()
print(*answers,sep='\n')
cs

 

문제링크:

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

'Algorithm > Python' 카테고리의 다른 글

[BOJ]9933. 민균이의 비밀번호  (0) 2019.09.09
[BOJ]2178. 미로찾기  (0) 2019.09.08
[BOJ]2331. 반복 수열  (6) 2019.09.06
[BOJ] 10451.순열 사이클  (0) 2019.09.05
[BOJ]10825. 국영수  (0) 2019.09.04

문제:

다음과 같이 정의된 수열이 있다.

  • D[1] = A
  • D[n] = D[n-1]의 각 자리의 숫자를 P번 곱한 수들의 합

예를 들어 A=57, P=2일 때, 수열 D는 {57, 74(=5^2+7^2=25+49),65,61,37,58,89,145,42,20,4,16,37, ...}이 된다. 그 뒤에는 앞서 나온 수들(57부터가 아니라 58부터)이 반복된다.

 

이와 같은 수열을 계속 구하다 보면 언젠가 이와 같은 반복수열이 된다. 이때, 반복되는 부분을 제외했을 때, 수열에 남게 되는 수들의 개수를 구하는 프로그램을 작성하시오. 위의 예에서는 {57,74,65,61}의 네 개의 수가 남게 된다.

입력:

첫째 줄에 A(1<=A<=9999),P(1<=P<=5)가 주어진다.

출력:

첫째 줄에 반복되는 부분을 제외했을 때, 수열에 남게 되는 수들의 개수를 출력한다.

풀이방법:

 DFS를 사용해서 풀어야 하는 문제이다. check라는 배열을 250000이라고 설정하고(최대 나올 수 있는 값은 9^5+9^5+9^5+9^5 이기 때문이다.) dfs로 하나씩 들어가면서 해당하는 값에 count를 할당한다. 이렇게 계속해서 값을 구하다가 check가 0이 아닌 값을 만난다면 그 값부터는 반복된다는 뜻이므로 그 check의 count에 1을 뺀 값이 정답이 되게 된다.

 이 문제로 예시를 들면 check[57]에 count를 1을 할당. ->check[74]에 2를 할당 -> check[65]에 3을 할당 -> check[61]에 4를 할당 -> check[37]에 5를 할당 -> check[58]에 6을 할당 -> check[89]에 7을 할당 -> check[145]에 8을 할당 -> check[42]에 9를 할당 -> check[20]에 10을 할당 -> check[4]에 11을 할당 -> check[16]에 12를 할당 -> check[37]에는 이미 5가 할당되어 있음. 따라서 57, 74, 65, 61만 남아야 하므로 답은 5-1인 4가 된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def next(A,P):
    a=str(A)
    answer=0
    for i in a:
        answer+=pow(int(i),P)
    return answer
 
def dfs(A,P,count,check):
    if check[A]!=0:
        return check[A]-1
    check[A]=count
    b= next(A,P)
    count+=1
    return dfs(b,P,count,check)
 
 
check=[0]*250000
A, P =map(int,input().split())
count=1
print(dfs(A,P,count,check))
cs

 

문제링크:

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

'Algorithm > Python' 카테고리의 다른 글

[BOJ]2178. 미로찾기  (0) 2019.09.08
[BOJ]2667. 단지번호붙이기  (0) 2019.09.07
[BOJ] 10451.순열 사이클  (0) 2019.09.05
[BOJ]10825. 국영수  (0) 2019.09.04
[BOJ]1373. 2진수 8진수  (0) 2019.09.03

문제:

1부터 N까지 정수 N개로 이루어진 순열을 나타내는 방법은 여러 가지가 있다. 예를 들어, 8개의 수로 이루어진 순열(3,2,7,8,1,4,5,6)을 배열을 이용해 표현하면 다음과 같다. 

[그림1]

또는 Figure 1과 같이 방향 그래프로 나타낼 수도 있다.

순열을 배열을 이용해 [그림1] 과 같이 나타냈다면, 임의의 노드 i에서 다른 노드 p로 간선을 이어 그래프로 만들 수 있다.

Figure 1에 나와있는 것 처럼, 순열 그래프(3,2,7,8,1,4,5,6) 에는 총 3개의 사이클이 있다. 이러한 사이클을 "순열 사이클"이라고 한다.

N개의 정수로 이루어진 순열이 주어졌을 때, 순열 사이클의 개수를 구하는 프로그램을 작성하시오.

입력:

첫째 줄에 테스트 케이스의 개수 T가 주어진다. 각 테스트 케이스의 첫째 줄에는 순열의 크기 N(2<=N<=1,000)이 주어진다. 둘째 줄에는 순열이 주어지며, 각 정수는 공백으로 구분되어 있다.

출력:

각 테스트 케이스마다, 입력으로 주어진 순열에 존재하는 순열 사이클의 개수를 출력한다.

풀이방법:

 DFS를 사용해서 풀 수 있는 문제이다. 1번 노드부터 시작해서 노드를 방문할 때마다 check를 1로 바꾼다. check가 1인 노드를 만나면 dfs를 종료하고 answer를 하나 증가시켜 순열 사이클의 개수를 나타내도록 하였다. 

 처음에는 DFS 함수를 재귀적으로 구현하고 제출했는데 런타임 에러가 발생하게 되었다. 코드를 봐도 런타임 에러가 발생할만한 곳이 없었는데 찾아보니 자체 시스템 상으로 재귀의 최대 한도가 정해져 있는데 이를 넘어가면 런타임 에러가 발생한다고 한다. 따라서 이 한도를 수정해야하는데 sys 모듈에 sys.setrecursionlimit() 라는 함수를 사용하면 재귀의 깊이 한도(?)를 조절 할 수 있다고 한다. 따라서 이 값을 2000으로 설정하고 코드를 다시 제출해 보았는데 통과할 수 있었다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import sys
def dfs(x,check,path):
    if check[x]:
        return
    check[x]=1
    dfs(path[x]-1,check,path)
 
sys.setrecursionlimit(2000)
for i in range(int(input())):
    n=int(input())
    path=list(map(int,input().split()))
    check=[0]*n
    ans = 0
    for j in range(n):
        if check[j] ==0:
            dfs(j,check,path)
            ans+=1
    print(ans)
cs

문제링크:

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

'Algorithm > Python' 카테고리의 다른 글

[BOJ]2667. 단지번호붙이기  (0) 2019.09.07
[BOJ]2331. 반복 수열  (6) 2019.09.06
[BOJ]10825. 국영수  (0) 2019.09.04
[BOJ]1373. 2진수 8진수  (0) 2019.09.03
[BOJ]9613. GCD 합  (0) 2019.09.02

문제:

가로, 세로 길이가 n인 정사각형으로된 체스판이 있습니다. 체스판 위의 n개의 퀸이 서로를 공격할 수 없도록 배치하고 싶습니다.

 

예를 들어서 n이 4인경우 다음과 같이 퀸을 배치하면 n개의 퀸은 서로를 한번에 공격 할 수 없습니다.

ㅜ=4일 때

 

체스판의 가로 세로의 길이 n이 매개변수로 주어질 때 , n개의 퀸이 조건에 만족 하도록 배치할 수 있는 방법의 수를 return하는 solution 함수를 완성해주세요.

 

풀이 방법:

 되추적 방법을 사용하는 대표적인 예시인 문제이다. 따라서 queens에서는 각 col별로 queen을 배치하는데 우선 promising이라는 함수에서 이전에 배치한 col을 기준으로 해당 인덱스에 queen을 배치할 수 있는지 판단해준다. 모든 방법을 다 판별해주는 방법도 생각할 수 있지만 그럴 경우 n이 커짐에 따라 많은 시간이 발생할 것이다. 따라서 promising이라는 되추적 판단을 해주는 함수로 인해서 많은 시간을 단축 할 수 있었다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def promising(i,col):
    k=0
    correct=True
    while (k<and correct):
        if (col[i]==col[k] or abs(col[i]-col[k])==i-k):
            correct=False
            break
        k+=1
    return correct
 
def queens(n,i,col,count):
    if (promising(i,col)):
        if (i==n-1):
            count.append(col)
        else:
            for j in range(n):
                col[i+1]=j
                queens(n,i+1,col,count)
def solution(n):
    col=n*[0]
    global count
    count=[]
    queens(n,-1,col,count)
    return len(count)
cs

 

 

문제 링크:

https://programmers.co.kr/learn/courses/30/lessons/12952

'Algorithm > Python' 카테고리의 다른 글

[BOJ]9935. 문자열 폭발  (0) 2019.08.29
[BOJ]1120. 문자열  (0) 2019.08.28
[BOJ]9465. 스티커  (0) 2019.08.24
[BOJ]1406. 에디터  (0) 2019.08.23
[BOJ]11053. 가장 긴 증가하는 부분 수열  (0) 2019.08.22

문제:

케빈 베이컨의 6단계 법칙에 의하면 지구에 있는 모든 사람들은 최대 6단계 이내에서 서로 아는 사람으로 연결될 수 있다. 케빈 베이컨 게임은 임의의 두 사람의 최소 몇 단계 만에 이어질 수 있는지 계산하는 게임이다.

 

예를 들면, 전혀 상관없을 것 같은 인하대학교의 이강호와 서강대학교의 민세희는 몇 단계만에 이어질 수 있을까?

 

천민호는 이강호와 같은 학교에 다니는 사이이다. 천민호와 최백준은 Backjoon Online Judge를 통해 알게 되었다. 최백준과 김선영은 같이 Startlink를 창업했다. 김선영과 김도현은 같은 학교 동아리 소속이다. 김도현과 민세희는 같은 학교에 다니는 사이로 서로 알고 있다. 즉, 이강호-천민호-최백준-김선영-김도현-민세희 와 같이 5단계만 거치면 된다.

 

케빈 베이컨은 미국 헐리우드 영화배우들끼리 케빈 베이컨 게임을 했을 때 나오는 단계의 총 합이 가장 적은 사람이라고 한다.

 

오늘은 Baekjoon Online Judge의 유저 중에서 케빈 베이컨의 수가 가장 적은 사람을 찾으려고 한다. 케빈 베이컨 수는 모든 사람과 케빈 베이컨 게임을 했을 때, 나오는 단계의 합이다.

 

예를 들어, BOJ의 유저가 5명이고, 1과 3, 1과 4, 2와 3, 3과 4, 4와 5가 친구인 경우를 생각해보자.

 

1은 2까지 3을 토해 2단계 만에, 3까지 1단계, 4까지 1단계, 5까지 4를 통해서 2단계 만에 알 수 있다. 따라서, 케빈 베이컨의 수는 2+1+1+2 = 6 이다.

 

2는 1까지 3을 통해서 2단계 만에, 3까지 1단계 만에, 4까지 3을 통해서 2단계 만에, 5까지 3과 4를 통해서 3단계 만에 알 수 있다. 따라서, 케빈 베이컨의 수는 2+1+2+3 = 8이다.

 

3은 1까지 1단계, 2까지 1단계, 4까지 1단계, 5까지 4를 통해 2단계 만에 알 수 있다. 따라서, 케빈 베이컨의 수는 1+1+1+2 =5 이다.

 

4는 1까지 1단계, 2까지 3을 통해 2단계, 3까지 1단계, 5까지 1단계 만에 알 수 있다. 4의 케빈 베이컨의 수는 1+2+1+1 = 5가 된다.

 

마지막으로 5는 1까지 4를 통해 2단계, 2까지 4와 3을 통해 3단계, 3까지 4를 통해 2단계, 4까지 1단계 만에 알 수 있다. 5의 케빈 베이컨의 수는 2+3+2+1 = 8이다.

 

5명의 유저 중에서 케빈 베이컨의 수가 가장 작은 사람은 3과 4이다.

 

BOJ 유저의 수와 친구 관계 입력으로 주어졌을 때, 케빈 베이컨의 수가 가장 작은 사람을 구하는 프로그램을 작성하시오.

 

입력:

첫째 줄에 유저의 수 N(2<=N<=100)과 친구 관계의 수 M(1<=M<=5,000)이 주어진다. 둘째 줄부터 M

개의 줄에는 친구 관계가 주어진다. 친구 관계는 A와 B로 이루어져 있으며, A와 B가 친구라는 뜻이다. A와 B가 친구이면, B와 A도 친구이며, A와 B가 같은 경우는 없다. 친구 관계는 중복되어 들어올 수도 있으며, 친구가 한 명도 없는 사람은 없다. 또, 모든 사람은 친구 관계로 연결되어져 있다.

 

출력:

첫째 줄에 BOJ의 유저 중에서 케빈 베이컨의 수가 가장 적은 사람을 출력한다. 그런 사람이 여러 명일 경우에는 번호가 가장 작은 사람을 출력한다.

 

풀이방법:

일단 모든 사람들에 대해서 케빈 베이컨의 수를 계산해야 하므로 BFS로 값을 탐색해야 한다고 생각했다.  for를 사용한 반복문은 입력값을 정리하기 위한 반복문이다. (보통 저는 bfs, dfs는 이와 같이 입력값들을 정리합니다.) answer는 각 사람 별로 count의 값을 담아주는 배열이고, 인덱스를 편리하기 관리하기 위해 1번 사람이 1번째 인덱스를 가지도록 하였다. person은 인덱스 값으로 교체해줘도 괜찮을 것 같지만 bfs 내에서 한 단계 이상 넘어간다면 여러 개의 값을 가져야 할 것 같아서 애초에 배열 값으로 넣게 되었다. 그리고 또한 자기 자신의 값을 탐색하지 않도록 자신의 값은 -1로 초기화 한 상태로 값을 넣었다.

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
def bfs(counts,person,friends,count):
    temp=[]
    for pe in person:
        for i in friends[pe]:
            if counts[i]==0:
                counts[i]=count
                temp.append(i)
    if len(temp):
        count+=1
        bfs(counts,temp,friends,count)
 
 
n,m=map(int,input().split())
friends=[[] for i in range(n+1)]
for i in range(m):
    a,b=map(int,input().split())
    if not a in friends[b]:
        friends[b].append(a)
        friends[b].sort()
    if not b in friends[a]:
        friends[a].append(b)
        friends[a].sort()
answers=[0]*(n+1)
answers[0]= -1
person=[1]
while not all(answers):
    counts=[0]*(n+1)
    count=1
    counts[person[0]]=-1
    bfs(counts,person,friends,count)
    answers[person[0]]=sum(counts)+1
    person[0]+=1
print(answers.index(min(answers[1:])))
cs

 

문제링크:

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

 

 

'Algorithm > Python' 카테고리의 다른 글

[BOJ]1406. 에디터  (0) 2019.08.23
[BOJ]11053. 가장 긴 증가하는 부분 수열  (0) 2019.08.22
[BOJ]4307. 개미  (0) 2019.08.06
[BOJ]1309. 동물원  (0) 2019.08.05
[BOJ]5430. AC  (0) 2019.08.04

문제:

자연수 N과 M이 주어졌을 때, 아래 조건을 만족하는 길이가 M인 수열을 모두 구하는 프로그램을 작성하시오.

  • 1부터 N까지 자연수 중에서 중복 없이 M개를 고른 수열

입력:

첫째 줄에 자연수 N과 M이 주어진다. (1<= M <= N < 8)

출력:

한 줄에 하나씩 문제의 조건을 만족하는 수열을 출력한다. 중복되는 수열을 여러 번 출력하면 안되며, 각 수열은 공백으로 구분해서 출력해야 한다.
수열은 사전 순으로 증가하는 순서로 출력해야 한다.

풀이 방법:

재귀적인 방법으로 길이가 M이 될 때까지 계속해서 넣어준다. 대신 이 문제에서는 중복을 허용하지 않았기 때문에 이에 대한 조건도 있어야 하고 증가하는 순서로 출력해야 하므로 배열에 들어있는 끝 값보다 클 때만 넣어줘야 한다는 조건 역시 필요하다. 이 문제에 대한 시리즈가 여러개 있는데 이에 맞는 조건을 넣어주면 된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def sequence(stack,numbers,M):
    if len(stack)==M:
        print(*stack)
        return
    else:
        for number in numbers:
            if not number in stack:
                stack.append(number)
                sequence(stack,numbers,M)
                stack.pop()
 
a,b=map(int,input().split())
numbers=list(range(1,a+1))
stack=[]
for number in numbers:
    if not number in stack:
        stack.append(number)
        sequence(stack,numbers,b)
        stack.pop()
cs

문제 링크:

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

'Algorithm > Python' 카테고리의 다른 글

[BOJ]5430. AC  (0) 2019.08.04
[BOJ]2312. 수 복원하기  (0) 2019.08.03
[BOJ]1009. 분산처리  (0) 2019.08.01
[Programmers]Lv 3.배달  (3) 2019.07.31
[Programmers]Lv 3. 순위  (0) 2019.07.30

문제:

 N개의 마을로 이루어진 나라가 있습니다. 이 나라의 각 마을에는 1부터 N까지의 번호가 각각 하나씩 부여되어 있습니다. 각 마을은 양방향으로 통행할 수 있는 도로로 연결되어 있는데, 서로 다른 마을간에 이동할 때는 이 도로를 지나야 합니다. 도로를 지날 때 걸리는 시간은 도로별로 다릅니다. 현재 1번 마을에 있는 음식점에서 각 마을로 음식 배달을 하려고 합니다. 각 마을로부터 음식 주문을 받으려고 하는데, N개의 마을 중에서 K 시간 이하로 배달이 가능한 마을에서만 주문을 받으려고 합니다. 다음은 N=5, K=3인 경우의 예시입니다.
 
 1번 마을에 있는 음식점은 [1,2,4,5]번 마을까지는 3이하의 시간에 배달할 수 있습니다. 그러나 3번 마을까지는 3시간 이내로 배달할 수 있는 경로가 없으므로 3번 마을에서는 주문을 받지 않습니다. 따라서 1번 마을에 있는 음식점이 배달 주문을 받을 수 있는 마을은 4개가 됩니다.
 
 마을의 개수 N, 각 마을을 연결하는 도로의 정보 road, 음식 배달이 가능한 시간 K가 매개변수로 주어질 때, 음식 주문을 받을 수 있는 마을의 개수를 return 하도록 solution 함수를 완성해주세요.
 

풀이 방법:

<Test 32 시간초과>

 DFS 방법을 사용해서 배달 거리가 K를 넘지 않을 때까지 stack 배열에 쌓으면서 계속해서 들어간다. 들어가는 과정에서 방문하는 마을은 모두 K시간 내 방문할 수 있는 곳이므로 count set에 담도록 한다.(set이므로 중복된 것을 넣어도 자동으로 사라진다.) stack 배열을 사용하는 이유는 사이클을 피하기 위해서이므로 깊은 노드를 방문하고 다시 나올 때는 stack에서 pop 하도록해서 다른 노드를 방문할 시간을 주도록 한다. 
 하지만 재귀 과정에서 문제가 발생해서 시간초과가 발생하는 것 같은데 무엇이 문제인지는 정확히 모르겠다. (정렬도 해봤지만 차이가 없었다.)
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
def delivery(stack,dist,now,roads,K):
    for r in roads[now]:
        temp=dist+r[1]
        if not r[0in stack and temp <=K:
            stack.append(r[0])
            count.add(r[0])
            delivery(stack,temp,r[0],roads,K)
            stack.pop()
    
def solution(N,road,K):
    roads=[[]for i in range(N+1)]
    for i in range(len(road)):
        if not road[i][0in roads[road[i][1]]:
            roads[road[i][1]].append((road[i][0],road[i][2]))
        if not road[i][1in roads[road[i][0]]:
            roads[road[i][0]].append((road[i][1],road[i][2]))
    stack=[1]
    dist=0
    global count
    count=set(stack)
    for r in roads[1]:
        temp=dist+r[1]
        if not r[0in stack and temp <=K:
            stack.append(r[0])
            count.add(r[0])
            delivery(stack,temp,r[0],roads,K)
            stack.pop()
    return len(count)
cs

 <2021.07.11 수정>

DFS와 같이 재귀적인 방법을 사용하는 것이 시간을 많이 소요할 것 같아 일반적으로 그래프에서 최소 거리를 구하는 방법으로 많이 사용되는 다익스트라 방법을 사용했다. 1에서 부터의 거리를 측정하기 때문에, 1에서 다익스트라로 거리를 구한 뒤에 K보다 작은 것의 갯수를 세서 반환하도록 한다.

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
import heapq
 
def dijkstra(start,dp,edge):
    dp[start] = 0
    heapq.heappush(heap,(0,start))
    
    while heap:
        weight, move = heapq.heappop(heap)
        
        if dp[move] < weight:
            continue
        for w, node in edge[move]:
            if w+weight< dp[node]:
                dp[node] = w+weight
                heapq.heappush(heap,(dp[node],node))
    return dp
 
def solution(N,road,K):
    edge = [[] for _ in range(N+1)]
    heap = []
    for i in road:
        a,b,c = i
        edge[a].append((c,b))
        edge[b].append((c,a))
    dp = [float('inf')]*(N+1)
    
    dp = dijkstra(1,dp,edge)
    answer = 0
    for i in range(1,V+1):
        if dp[i] <= K:
            answer +=1
    return answer
cs

문제 링크:

https://programmers.co.kr/learn/courses/30/lessons/12978

'Algorithm > Python' 카테고리의 다른 글

[BOJ]15649. N과M(1),(2)  (0) 2019.08.02
[BOJ]1009. 분산처리  (0) 2019.08.01
[Programmers]Lv 3. 순위  (0) 2019.07.30
[Programmers]Lv3. 가장 먼 노드  (0) 2019.07.29
[Programmers]Lv 4. 3xn 타일링  (2) 2019.07.28

문제:

 신종 바이러스인 웜 바이러스는 네트워크를 통해 전파된다. 한 컴퓨터가 웜 바이러스에 걸리면 그 컴퓨터와 네트워크 상에서 연결되어 있는 모든 컴퓨터는 웜 바이러스에 걸리게 된다.

 예를 들어 7대의 컴퓨터가 <그림1>과 같이 네트워크 상에서 연결되어 있따고 하자. 1번 컴퓨터가 웜 바이러스에 걸리면 웜 바이러스는 2번과 5번 컴퓨터를 거쳐 3번과 6번 컴퓨터까지 전파되어 2,3,5,6 네 대의 컴퓨터는 웜 바이러스에 걸리게 된다. 하지만 4번과 7번 컴퓨터는 1번 컴퓨터와 네트워크상에서 연결되어 있지 않기 때문에 영향을 받지 않는다.

  어느 날 1번 컴퓨터가 웜 바이러스에 걸렸다. 컴퓨터의 수와 네트워크 상에서  서로 연결되어 있는 정보가 주어질 때, 1번 컴퓨터를 통해 웜 바이러스에 걸리게 되는 컴퓨터의 수를 출력하는 프로그램을 작성하시오,

입력:

 첫째 줄에는 컴퓨터의 수가 주어진다. 컴퓨터의 수는 100 이하이고 각 컴퓨터에는 1번 부터 차례대로 번호가 매겨진다. 둘째 줄에는 네트워크 상에서 직접 연결되어 있는 컴퓨터의 쌍의 수가 주어진다. 이어서 그 수만큼 한 줄에 한 쌍씩 네트워크 상에서 직접 연결되어 있는 컴퓨터의 번호 쌍이 주어진다.

출력:

 1번 컴퓨터가 웜 바이러스에 걸렸을 때, 1번 컴퓨터를 통해 웜 바이러스에 걸리게 되는 컴퓨터의 수를 첫째 줄에 출력한다.

풀이 방법:

 1에 연결되어 있는 네트워크를 다 찾아야 하므로 깊게 계속 파고 들어가는 것 보다 너비를 우선 해서 탐색하는 편이 더 좋다. 우선 양방향으로 퍼질 수 있으므로 인덱스를 컴퓨터의 번호로 해서 리스트로 이동할 수 있는 컴퓨터를 담아두었다. 그 다음에는 answer리스트를 만들어두고 answer에는 없지만 갈 수 있는 곳이면 answer에 담고 이동을 하는 방식으로 답을 구하였다. 1번 컴퓨터를 제외한 컴퓨터의 수가 정답이므로 마지막에 1을 뺐다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
n=int(input())
virus=int(input())
computer=[[] for i in range(n+1)]
for i in range(virus):
    a,b=map(int,input().split())
    if not a in computer[b]:
        computer[b].append(a)
    if not b in computer[a]:
        computer[a].append(b)
answer=[1]
def bfs(now):
    global answer
    for i in computer[now]:
        if not i in answer:
            answer.append(i)
            bfs(i)
bfs(1)
print(len(answer)-1)
cs


'Algorithm > Python' 카테고리의 다른 글

[BOJ]2075. N번째 큰 수  (0) 2019.07.23
[BOJ] 11279,1927,11286 최대힙,최소힙,절대값 힙  (0) 2019.07.21
[BOJ]1260. DFS와 BFS  (0) 2019.07.19
[BOJ]2164. 카드2  (0) 2019.07.18
[BOJ]4949. 균형잡힌 세상  (0) 2019.07.17

문제:

그래프를 DFS로 탐색한 결과와 BFS로 탐색한 결과를 출력하는 프로그램을 작성하시오. 단, 방문할 수 있는 정점이 여러 개인 경우에는 정점 번호가 작은 것을 먼저 방문하고, 더 이상 방문할 수 있는 점이 없는 경우 종료한다. 정점 번호는 1번부터 N번까지이다.

입력:

첫째 줄에 정점의 개수 N(1<=N<=1,000), 간선의 개수 M(1<=M<=10,000), 탐색을 시작할 정점의 번호 V가 주어진다. 다음 M개의 줄에는 간선이 연결하는 두 정점의 번호가 주어진다. 어떤 두 정점 사이에 여러 개의 간선이 있을 수 있다. 입력으로 주어지는 간선은 양방향이다.

출력:

첫째 줄에 DFS를 수행한 결과를, 그 다음 줄에는 BFS를 수행한 결과를 출력한다. V부터 방문된 점을 순서대로 출력하면 된다.

풀이 방법:

양방향으로 이동가능이 하므로 2중배열로 만들어서 경로를 저장했다. 인덱스가 출발하는 정점이고 그 안에 들어있는 값들은 도착하는 정점이다.
DFS는 지금 마지막으로 들어온 정점이 중요하므로 그 정점이 가지고 있는 경로 중에 지나지 않은 곳으로 다시 들어가는 재귀방식으로 짜주면 된다.
BFS는 계속해서 배열을 누적하는 방식으로 진행했다. BFS에 계속 담아두고 반복문으로 하나하나 탐색하며 방문하지 않은 정점으로 이동하는 방식으로 진행했다. BFS에는 예외처리 구문이 들어가 있다. 왜냐하면 처음에는 없이 했더니 런타임에러가 발생하게 되었고, 그 이유를 알아보니 시작하는 정점이 1이라고 줬지만 1로 시작하는 정점이 없을 때 문제가 발생했다. 따라서 이 문제를 해결하기 위해 예외처리구문을 넣었다.

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
37
38
n,m,V=map(int,input().split())
path=[[]for i in range(n+1)]
for i in range(m):
    a,b=map(int,input().split())
    if not a in path[b]:
        path[b].append(a)
    if not b in path[a]:
        path[a].append(b)
for p in path:
    p.sort()
 
DFS=[]
def dfs(now):
    DFS.append(now)
    for i in path[now]:
        if i in DFS:
            continue
        dfs(i)
    return
dfs(V)
print(*DFS)
def bfs(now):
    global BFS
    temp=[]
    if len(now)==n:
        return
    try:
        for i in now:
            for j in path[i]:
                if not j in BFS:
                    BFS.append(j)
        bfs(BFS)
    except:
        return
    return
BFS=[V]
bfs(BFS)
print(*BFS)
cs


'Algorithm > Python' 카테고리의 다른 글

[BOJ] 11279,1927,11286 최대힙,최소힙,절대값 힙  (0) 2019.07.21
[BOJ]2606. 바이러스  (0) 2019.07.20
[BOJ]2164. 카드2  (0) 2019.07.18
[BOJ]4949. 균형잡힌 세상  (0) 2019.07.17
[BOJ]2004. 조합 0의 개수  (0) 2019.07.16

문제 설명:

주어진 항공권을 모두 이용하여 여행경로를 짜려고 합니다. 항상 "ICN" 공항에서 출발합니다.

항공권 정보가 담긴 2차원 배열 tickets가 매개변수로 주어질 때, 방문하는 공항 경로를 배열에 담아 return 하도록 solution 함수를 작성해주세요.

문제 풀이:

이 문제도 역시 경로를 탐색을 하는 문제이므로 깊이/너비 우선 탐색을 하는 문제이다. 또한 제한 사항 중에 주어진 항공권은 모두 사용해야 하고, 모든 도시를 방문을 할 수 없는 경우는 주어지지 않습니다. 라고 하였으니 항상 답이 있다고 가정을 하고 풀면 된다.

먼저 표의 현황을 깔끔하게 정리를 하기 위해서 tickets을 반복문으로 돌아가면서 이를 딕셔너리 타입(해시) 방식으로 정렬을 하였다. 매번 추가하면서 정렬을 한 이유는 만약 가능한 경로가 여러개라면 알파벳 순서가 앞서는 경로를 우선으로 해야하기 때문이다.


티켓을 정리한 뒤에 재귀적으로 탐색을 하는 함수인 travel에 ticket의 정보를 담고 있는 answer_set, 실제 경로인 answer, 출발하는 공항의 이름인 start, 그리고 모든 항공권을 사용했는지 탐색해야하므로 티켓의 갯수인 K 와 몇 개를 사용했는지 알려주는 count를 사용하였다.


처음에는 무조건 ICN에서 시작을 한다는 조건이 있었으므로 초기값은 ICN으로 시작한다. travel 함수에는 세 가지 조건이 존재한다. 


1. count == K 일 때

종료 조건으로 모든 티켓을 다 사용한 경우에 해당한다. 따라서 True를 반환한다.

2. 잘못 경로를 탐색해서 들어갔을 경우

해시 구조를 통해서 티켓을 정리했다보니 B 공항으로 도착을 하긴 했지만 B 공항에서 출발을 하는 티켓이 없을 수도 있다. 따라서 이 경우에 이 값을 찾으려 하면 error가 발생하기 때문에 예외처리구문을 사용해서 이 case를 탐지했다. 이 경우가 발생한거면 잘못된 경로를 온 것이기 때문에 answer의 마지막 값을 빼주고 잘못된 경로이므로 False를 반환한다.

3. 위 두 경우가 아닐 때

해시로 정리한 티켓을 기준으로 하나씩 경로를 늘려가면서 탐색해본다. 


위 과정을 거치다보면 answer를 구할 수 있게 된다.


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
import copy
def travel(answer_set,answer,start,K,count):
    answer.append(start)
    if count==K:
        return True
    try:
        answer_set[start]
    except:
        answer.pop()
        return False
    for i in range(len(answer_set[start])):
        end=answer_set[start][i]
        count+=1
        temp_set=copy.deepcopy(answer_set)
        temp_set[start]=temp_set[start][:i]+temp_set[start][i+1:]
        boolean=travel(temp_set,answer,end,K,count)
        if boolean:
            return True
        else:
            count-=1
    answer.pop()
    return False
def solution(tickets):
    answer_set={}
    for ticket in tickets:
        if ticket[0in answer_set:
            answer_set[ticket[0]].append(ticket[1])
            answer_set[ticket[0]].sort()
        else:
            answer_set[ticket[0]]=[ticket[1]]
    answer=[]
    count=0
    start="ICN"
    travel(answer_set,answer,start,len(tickets),count)
    return answer
cs


'Algorithm > Python' 카테고리의 다른 글

[BOJ]2869. 달팽이는 올라가고 싶다.  (0) 2019.07.06
[BOJ]1011. Fly me to the Alpha Centauri  (0) 2019.07.05
[Programmers]Lv 3. 네트워크  (2) 2019.07.03
[BOJ]11057. 오르막 수  (0) 2019.07.01
[BOJ]1436. 영화감독 숌  (0) 2019.06.29

+ Recent posts