[코딩테스트] 그래프의 표현

reference : 2021 코딩테스트 기초(최백준) 강의를 공부하며 정리한 내용입니다.

그래프의 표현

  • 그래프 저장하는 방법(정점, 간선)
  • 정점의 저장 : 개수 v (1~v or 0~(v-1)) ex) {1,2,3,4,5,6}
  • 간선 : ex) {(1,2), (1,5), (2,5), (2,3), (3,4), (2,4), (4,5), (4,6)}
  • 효율 : 한 정점 v와 연결된 모든 정점을 구하는 시간
    • 인접 행렬 : 2차원 행렬, 배열
    • 인접 리스트 : 리스트 이용, 하나의 정점과 연결되어 있는 모든 정점 저장하는 방식

인접 행렬

  • 정점의 개수 V 일때 V x V 크기의 이차원 행렬 이용
  • A[i][j] = 1 (i -> j 간선 있을때), 0 (없을 때)
  • 공간 : V²
  • 효율성 : V
  • 장점 : 임의의 두 정점 사이에 간선이 있는지 없는지 쉽게 판단 가능하다. O(1)
  • 단점 : 공간을 너무 많이 사용한다. (없는 간선도 저장하기 때문) 그래서 잘 사용 안한다…

인접 리스트

  • 리스트를 이용해서 구현. A[i] = i와 연결된 정점을 리스트로 포함함.
  • A[1] = 2,5 / A[2] = 1,3,4,5 …
  • 공간 : E(간선)
  • 효율성 : O(정점의 차수)
  • u, v 사이 간선이 있는지 확인 위해선 A[u] 모든 값들을 비교해줘야함. 차수만큼 시간이 걸린다.
  • 링크드리스트 이용. C++ vector, Java ArrayList, Python list
  • 가중치는 (정점, 가중치) 형태로 같이 저장 ex) A[1] = (2,2) (5,7)

간선 리스트

  • C++, java 에서 vector, arraylist 사용할 수 없는데 Linked List 구현의 자신이 없을때 사용하는 방법.
  • 배열 이용해 구현.
  • 간선을 모두 저장하고 있음. ex) E[0] = 1 2, E[1] = 1 5…
  • 각 간선의 앞 정점을 기준으로 개수를 센다, 앞에서 센걸 누적으로 더해줌.
  • 효율성 O(차수)

ABCDE (13023번)

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

문제

  • 총 N명의 친구 관계가 주어졌을 때 다음과 같은 친구 관계가 존재하는지 구하는 문제
  • A는 B와 친구다. B는 C와 친구다. C는 D와 친구다. D는 E와 친구다.

풀이

  • 인접 행렬 : 임의의 두 정점 사이에 간선이 있는지 확인 O(1)
  • 리스트 : 한 정점과 연결된 모든 간선 O(차수)
  • A->B 간선 리스트 다 찾고, C->D 간선 리스트 다 찾고 A->B->C->D->E니까 B->C 가능한지 찾아야 함. 이 때 인접행렬 사용. 있으면 1, 아니면 0
  • D->E 인접 리스트 이용해서 찾기.
  • 더 쉬운 풀이법 있지만 배운 개념을 다 활용해보기 위해..
import java.util.*;

class Edge{
	int from, to;
	//c++,파이썬과 다르게 임의의 두 수를 묶는게 불가능해서 클래스 만듬
	Edge(int from, int to){
		this.from = from;
		this.to = to;
	}
}

public class Main {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt(); //사람 수
		int m = sc.nextInt(); //친구 관계 수
		boolean[][] a = new boolean[n][n]; //인접행렬
		ArrayList<Integer>[] g = (ArrayList<Integer>[]) new ArrayList[n]; //인접리스트
		ArrayList<Edge> edges = new ArrayList<Edge>(); //모든 간선 저장
		for(int i=0; i<n; i++) {
			g[i] = new ArrayList<Integer>(); //인접리스트 사용 위해선 각각 객체 생성시켜줘야함
		}
		for(int i=0; i<m; i++) {
			int from = sc.nextInt();
			int to = sc.nextInt();
			//간선리스트, 양방향이니까 각각 저장
			edges.add(new Edge(from, to));
			edges.add(new Edge(to, from));
			//인접행렬도 양방향 저장
			a[from][to] = a[to][from] = true;
			//인접리스트에도 양방향 저장
			g[from].add(to);
			g[to].add(from);
		}
		m *= 2; //양방향이라 간선 두배
		for(int i=0; i<m; i++) {
			for(int j=0; j<m; j++) {
				int A = edges.get(i).from;
				int B = edges.get(i).to;
				int C = edges.get(j).from;
				int D = edges.get(j).to;
				if(A==B||A==C||A==D||B==C||B==D||C==D) {
					continue; //A,B,C,D 같은 게 있는지 없는지 확인
				}
				if(!a[B][C]) continue; //B->C 간선 있는지 확인
				for(int E : g[D]) { //마지막으로 D->E 확인
					if(A==E||B==E||C==E||D==E) {
						continue;
					}
					System.out.println(1);
					System.exit(0);
				}
			}
		}
		System.out.println(0);
	}
}

-> 처음 배우는 개념이기도 하고… 구현 방법을 처음 봐서 코드 이해하는 것만해도 힘들었다^_ㅜ 내일 문제 풀 수 있겠지..? 하 하 하

댓글남기기