본문 바로가기
WIL

12/04 WIL

by 달리는 꿈나무 2022. 12. 4.

1.  알고리즘 관련 공부

이번 주는 공부했던 알고리즘 지식을 정리하려 한다.

그래프 예시

그래프

  • 노드와 간선의 집합
  • 방향이 설정되어 있으면 방향 그래프
  • 방향이 설정되어 있지 않으면 무방향 그래프
  • 간선에 값이 설정되어 있으면 가중치를 뜻한다. 이러한 그래프는 가중치 방향 그래프라 한다.

 

 

인접 행렬

  • 프로그래밍에서 그래프를 표현할 때 사용하는 행렬
  • 기본적으로 인접행렬을 입력할 떄 행 -> 열의 방향으로 그래프가 진행 된다고 보면 된다.
  • 노드 a가 b로 갈 때 인접 그래프가 g라고 하면 g[a][b] = 1 이렇게 표현한다.
  • 가중치가 있으면 g[a][b] = (가중치) 라고 표현한다.
  • 무방향 그래프의 경우  g[a][b] = 1 ,  g[b][a] = 1 이렇게 행과 열을 바꾸어 두 번 지정해주어야 한다.

 

 

방문 체크 리스트

  • dfs 혹은 bfs를 사용하면 기본 적으로 사용하는 체크 리스트
  • 노드에 방문을 했는지 체크하는 리스트로 방문을 안 했다면 값이 0이고 방문을 했다면 1로 값을 지정한다.
  • dfs를 사용할 때 백트래킹을 걸어 줄 것이면 
    • check[i] = 1
    • dfs(s)
    • check[i]=0
  • 이렇듯이 다음 dfs가 메모리 스택에 저장되어 있는 다음 순서에 체크를 미방문으로 해주어야 백트래킹이 된다.

 

 

예제)  인접 행렬(가중치 방향 그래프)

 

아래 그림과 같은 그래프 정보를 인접행렬로 표현해보세요.

 

그래프 정보

입력설명

첫째 줄에는 정점의 수 N(2<=N<=20)와 간선의 수 M가 주어진다.

그 다음부터 M줄에 걸쳐 연결정보와 거리비용이 주어진다.

 

출력설명

인접행렬을 출력하세요.

 

입력예제 1

6 9

1 2 7

1 3 4

2 1 2

2 3 5

2 5 5

3 4 5

4 2 2

4 5 5

6 4 5

 

출력예제1

0 7 4 0 0 0

2 0 5 0 5 0

0 0 0 5 0 0

0 2 0 0 5 0

0 0 0 0 0 0

0 0 0 5 0 0

 

 

해설)

이 문제의 경우 인접행렬을 표현하는 것을 물어보는 기초적인 문제로 위에 적은 인접행렬의 개념과 가중치를 지정하는 표현 방식을 생각하면 된다. 다만 좌표가 1 부터 n 까지인지, 0 부터 n-1 까지인지를 유념하면서 인접행렬을 초기화하고 그에 따른 출력 방법도 달라져야 할 것이다. 가장 간단한 그래프 문제이므로 무방향 그래프 표현 방식도 주석으로 넣어 놨다.

 

# 그래프 - 노드와 간선의 집합
# 방향이 설정되어 있으면 방향 그래프
# 간선의 값까지 설정되어 있으면 가중치 방향 그래프
# 무방향 그래프, 가중치 방향 그래프 순서로 해볼 것이다.

# 인접 행렬을 통해 그래프를 표현한다.
# 행 -> 열 방향으로 된다고 알아야한다.

# 인접그래프가 g라고 하면
# g[a][b] = 1 이렇게 표현한다.
# 그러면 a -> b 이렇게 간다는 것을 표현할 수 있다.

# 무방향 그래프는 a -> b, b -> a 이렇게 두 곳을 1로 해야한다.
#  g[a][b] = 1 , g[b][a] 하나씩 해가는 거다.


# 무방향 그래프 그리기
# n,m = map(int, input().split())

# # 행렬 표현식 외워두자 n이 주어진다면 n+1을 범위로 잡는다. 
# # 1 부터 n까지 돌 거다.
# g=[[0]*(n+1) for _ in range(n+1)]

# for i in range(m):
#     a,b = map(int, input().split())
#     # 무방향 그래프
#     g[a][b] = 1
#     g[b][a] = 1

# for i in range(1,n+1):
#     for j in range(1,n+1):
#         print(g[i][j], end=' ')
#     print()



# 문제 해결
n,m = map(int, input().split())

# 행렬 표현식 외워두자 n이 주어진다면 n+1을 범위로 잡는다. 
# 1 부터 n까지 돌 거다.
g=[[0]*(n+1) for _ in range(n+1)]

for i in range(m):
    a,b,c = map(int, input().split())
    # 단방향 그래프와 가중치 설정
    g[a][b] = c

for i in range(1,n+1):
    for j in range(1,n+1):
        print(g[i][j], end=' ')
    print()

 

 

 

예제)  경로 탐색(그래프 DFS)

 

방향그래프가 주어지면 1번 정점에서 N번 정점으로 가는 모든 경로의 가지 수를 출력하는 프로그램을 작성하세요.

아래 그래프에서 1번 정점에서 5번 정점으로 가는 가지 수는

 

문제 그래프

 

1 2 3 4 5

1 2 5
1 3 4 2 5
1 3 4 5

1 4 2 5

1 4 5

총 6 가지입니다.
그래프에서 경로를 방문한 노드는 중복해서 방문하지 않습니다.

 

입력설명
첫째 줄에는 정점의 수 N(2<=N<=20)와 간선의 수 M가 주어진다. 그 다음부터 M줄에 걸쳐 연 결정보가 주어진다.

출력설명
총 가지수를 출력한다.

 

입력예제 1

5 9

1 2

1 3

1 4

2 1

2 3

2 5

3 4

4 2

4 5

 

출력예제 1 6

 

 

해설)

위에서 연습한 인접행렬과 방문 체크 리스트를 가지고 만드는 DFS() 문제다. 경로 탐색은 DFS()를 사용해야하는 것을 잊지 말자.

인식해야될 조건은 1. 방향 그래프, 2. 가중치 없음, 3. 출발 노드는 1 이다.

정지 조건은 방문한 노드가 최종 노드일 때다. 즉 V == N이다. 전에 풀었던 문제들도 기본적으로 L == N 즉, 레벨이 N이 될 때였다.

여기서도 방문 가능한 노드를 찾아야 하기에 else문에서 for문을 돌리면서 다른 노드가 현재 노드와 이어져 있는지 and 방문을 했는 지를 보고 나서 방문하고, DFS(), 방문 취소 이런 로직을 넣어줘야한다.

 

# 방문 체크 리스트 , 인접 행렬 두 개가 필요하다.
# 경로 탐색은 DFS()를 사용해야한다.

def DFS(v):
    global cnt
    # 목적 노드에 도착했다면 DFS() 정지
    if v==n:
        cnt+=1

        # 도착했을 때 경로 리스트에 저장된 노드를 다 뽑자
        for x in path:
            print(x, end=" ")
        print()

    else: # 가지(상태 노드) 뻗기
        for i in range(1,n+1): # i가 방문하려는 노드다. 1부터 5까지
            # 방문 로직
            # 인접행렬이 연결이 되어있습니까?
            if g[v][i] == 1:
                if ch[i] == 0:
                    ch[i] = 1

                    # i로 가야하니까 i를 경로 리스트에 추가
                    path.append(i)
                    DFS(i)

                    # 백트래킹
                    path.pop() # 넣었던 거 다시 빼야 백트래킹 된다.
                    ch[i] = 0


if __name__=='__main__':
    n,m = map(int, input().split())

    # 인접 리스트 생성
    g = [[0]*(n+1) for _ in range(n+1)]

    # 방문 체크 리스트 생성
    ch = [0]*(n+1)

    for i in range(m):
        a,b = map(int,input().split())
        # 방향 그래프니까 a,b만. 중요!
        g[a][b] = 1

    cnt = 0

    # 방문 경로 
    path = []

    # 방문 시작 노드는 체크해주자
    ch[1] = 1
    path.append(1)
    DFS(1)
    print(cnt)

 

'WIL' 카테고리의 다른 글

12/18 WIL  (0) 2022.12.18
12/11 WIL  (1) 2022.12.11
11/27 WIL  (0) 2022.11.27
11/12 WIL  (0) 2022.11.12
11/06 WIL  (0) 2022.11.06