강한 결합 요소를 찾는 알고리즘

2022. 12. 14. 01:20·BackEnd/알고리즘 공부

일단 알고리즘을 설명하기전 강한 결합 요소부터 설명할려 한다. 강한 결합요소 즉, SCC는 그래프에서 하나의 노드에서 시작해 다른 노드까지 갔다가 다시 자신의 노드로 되돌아 올 수 있는 최대 컴포넌트의 모임이다.

이 그래프를 보면 9에서 시작해 (4,5,7)과 (3,6,8) 과 9로 나눌 수 있다는 것을 알 수 있다. 즉, 여기서 SCC는 3개가 나온다.

SCC를 찾는 알고리즘은 2가지가 있다. 그 중 한가지인 코사리주의 알고리즘은 학교 알고리즘 시간에 배웠다. 그 때 교수님께서 다른 방법인 타잔 알고리즘이 있다고 한 것이 기억에 난다. 운이 좋게도 이번 동아리 스터디에서 타잔 알고리즘에 대해 알려줘 공부해 보았다.

 

코사리주 알고리즘

코사리주 알고리즘은 dfs를 2번하여 강한 결합 요소를 찾는 것이다.

첫번째 dfs를 수행해 스택에 더 이상 갈 곳이 없는 노드를 순서대로 삽입한다.

두번째 dfs를 하기 전 그래프를 모두 반대 방향으로 바꾼 뒤 시작 노드를 스택의 top으로 하여 dfs를 한번 더 수행 한다. 이 때 탐색 되는 모든 정점을 SCC로 묶는다. 스택이 비어있을 때까지 반복한다. 만약 top에 위치한 정점이 이미 방문했다면 pop만 한다.

 

타잔 알고리즘 방법

타잔 알고리즘은 DFS를 한번만 수행해 SCC를 찾는 방법이다. 코사리주 알고리즘 보다는 SCC를 찾을 때 적용이 더 쉬워 코딩 테스트에서 자주 사용한다고 한다.

제일 처음 시작 할 노드를 정하고 방문하는 순서에 따라 각 정점에 고유한 id값을 매긴다. 방문 할 때마다 해당 정점을 스택에 삽입한다. 방문할 정점이 여러개이면 사전 순으로 더 낮은 정점부터 방문한다.

위 그래프에서는 9부터 시작한다고 하면 9→5→4→7을 방문하고 각각 1,2,3,4의 id값을 갖는다. 그리고 스택에는 9547이 들어가 있다. 7은 다시 5로 가게된다. 5로 가게 되면 id값은 2로 바뀌고 나머지 4도 id값이 2로 바뀌게 된다. 그 후 5,4,7,이 pop이 된다. 다시 9로가 반대편 8→3→6도 똑같이 수행하고 SCC를 만든 뒤 스택에는 9만 남게 된다. 이렇게 SCC 3개를 만들 수 있다.

 

타잔 알고리즘 구현

vector<int> adj[20202]; //입력 받을 
int d[20202]; //id관리
int f[20202]; //방문했는지 검사
int id; int sccid;
stack<int> st; // dfs돌면서 stack에 삽입
vector<vector<int>> SCC; //SCC 요소 끼리 결합
int sd[20202]; //sccid 관리 
int dfs(int x //현재 노드){
	if(f[x]==true) return -1; //방문 했으면 return;
  d[x]= ++id; //방문한 순서대 id값 입력
	st.push(x);
	int parent = d[x]; 
	for(int y : adx[x]){ // 현재 노드가 갈 수 있는 모든 노드 방문
   if(d[x] == 0) parent = min(parent,dfs(y)); 
   // 현재 노드를 아직 방문 안 했으면 방문 할 요소 중 parent 작은 걸로 초기화
	 else if(!f[y]) parent = min(parent, d[y]); 
   // 방문은 했지만 scc에 안 들어갔으면 현재 노드와 방문했던 것중 parent작은 걸로 초기화
	}
	if(parent == d[x]){ //부모와 자신이 같음 즉 더 이상 방문할 곳 이 없음
	  vector<int> scc;
	  while(true){
	    int t = st.top(); //stack의 top요소부터 고려
	    st.pop();
			sd[t] = sccid; 
		  f[t] = true;
			scc.push_back(t); //scc를 만든다.
		  if(t==x)break;
	  }
    SCC.push_back(scc);
		sccid++;
	}
  return parent;
}

정리

이번에는 타잔 알고리즘에 대해 구현해 보았다. 구현해본 결과 코사리주 알고리즘 보다는 더 빠르게 구현 할 수 있을 것 같다. 이제 이에 관한 백준 문제를 풀어가면서 알고리즘을 익혀야겠다.

'BackEnd > 알고리즘 공부' 카테고리의 다른 글

구간 합 구하기(JAVA)  (0) 2022.12.24
LCS 구하기  (0) 2022.12.14
디닉 알고리즘  (0) 2022.12.14
에드몬드 카프 알고리즘  (0) 2022.12.14
세그먼트 트리  (0) 2022.12.14
'BackEnd/알고리즘 공부' 카테고리의 다른 글
  • LCS 구하기
  • 디닉 알고리즘
  • 에드몬드 카프 알고리즘
  • 세그먼트 트리
인프라 감자
인프라 감자
  • 인프라 감자
    삶은 인프라
    인프라 감자
  • 전체
    오늘
    어제
    • 분류 전체보기 (243)
      • 클라우드&인프라 (28)
        • 인프라 공부 (4)
        • AWS 구조와 서비스 (18)
        • 클라우드 공부 (4)
        • Terraform (2)
      • AWS Cloud School (13)
        • project (5)
        • Linux, Network (6)
        • Docker (2)
      • BackEnd (162)
        • JAVA 공부 (15)
        • 알고리즘 공부 (71)
        • MySQL 문제 풀기 (8)
        • 스프링 핵심 원리 - 기본편 (18)
        • 스프링 MVC 1편 (4)
        • 자바 ORM 표준 JPA 프로그래밍 (21)
        • 실전! 스프링 부트와 JPA 활용1 (8)
        • 실전! 스프링 부트와 JPA 활용2 (5)
        • 스프링 데이터 JPA (8)
        • Querydsl (4)
      • 혼자하는 프로젝트 (32)
        • 배달의 민족 클론코딩 (7)
        • 나만의 프로젝트 (10)
        • 스프링 부트로 구현한 웹 (15)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

    • Email
    • GitHub
  • 공지사항

  • 인기 글

  • 태그

    백트래킹
    쿼드 압축
    자동 배포
    dp
    자바
    VPN
    디팬스 게임
    프로그래머스
    중첩 선언
    네트워크 기본 용어
    다이나믹 프로그래밍
    상속
    유니온 파인드
    완전탐색
    스프링 핵심 원리-기본편
    조합
    이것이 자바다
    정렬
    querydsl
    linux
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
인프라 감자
강한 결합 요소를 찾는 알고리즘
상단으로

티스토리툴바