Algorithm/DFS BFS

[BFS/DFS] 여행 경로

Maison 2025. 2. 12. 20:15

 

접근

위의 문제는 모든 나열된 경우의 수를 파악해야하기 때문에 1)완전탐색이 필요하고 그래프 형태로 표시할 수 있기때문에 2)DFS로 접근한다. 또한 명확한 최적의 해가 존재하기에 3)BackTracking 기법을 사용한다.

 

 

BFS와 백트래킹 알고리즘 구현시 필요 조건

 

1) BFS의 필요조건

  • 최종 출력값
  • 방문 여부 확인용 변수
  • 현재 노드
  • 방문 가능 조건
  • 동작
    • 방문 가능하다면 방문.
    • 종료 조건에 도달시 종료 (특정 지점에 도달 및 etc)

 

2) 백트래킹의 필요 조건

 

  • 최종 출력값
  • 방문 여부 확인용 변수
  • 현재 노드
  • 방문 가능 조건
  • 동작
    •  방문 가능하다면 방문.
    • 조건에 만족되지 않는 경우 되돌아오기. -> 되돌아오는 return값 유형별로 확인하기.
    • 되돌아올때, 방문 여부 확인용 변수와 최종 출력값을 되돌려줘야 한다.

 

구현

  • 최종 출력값 : 방문 공항 경로 path
  • 방문 여부 확인용 변수 : 티켓 사용 여부 확인용 변수 map<pair<string,string>,int>>
    **동일한 티켓이 두개 이상 있을 수 있음!
  • 현재 노드 : 현재 도착한 공항
  • 방문 가능 조건 : {현재 도착 공항,방문하려는 공항} 쌍이 존재해야함 && 해당 티켓이 여분이 존재해야함
  • 동작
    • 방문 가능시 방문
    • 방문 조건 확인용 변수들 업데이트( 공항경로 & 티켓 사용여부 )
    • 조건에 만족하는 경우, 동작을 끝내기 ( return값을 true로 설정하여 )
    • 조건에 만족하지 않을 경우, 방문 조건 확인용 변수들 롤백

 

코드

#include <iostream>
#include <vector>
#include <algorithm>
#include <stack>
#include <unordered_set>
#include <map>
#include <unordered_map>

using namespace std;

bool dfs(unordered_map<string,vector<string>> graph,map<pair<string,string>,int>& used,vector<string>& path,int ticket_num)
{
    if(path.size()>=ticket_num+1)
    {
        result=path;
        return true;
    }
    
    string cur_city=path.back();

    for(auto city : graph[cur_city])
    {
        if(used[{cur_city,city}]==1) //같은 항공권이 여러장 있을 수 있음.
        {
            used[{cur_city,city}]--;
            path.push_back(city);
            if(dfs(graph,used,path,ticket_num)==true) return true;
            path.pop_back();
            used[{cur_city,city}]++;
        }
    }

    return false;

    /*
    동작 구현
    1) 동작 가능 여부
     - 인접 티켓 확인
     - 사용 가능여부 확인
    */
}

vector<string> solution(vector<vector<string>> tickets)
{
    /*
    1) 출력 (path)
    2) 사용여부 (used)
    3) 노드 (티켓)
    4) 동작
    */
    unordered_map<string,vector<string>> graph;
    map<pair<string,string>,int> used;
    vector<string> path;

    for(auto ticket : tickets)
    {
        graph[ticket[0]].push_back(ticket[1]);
        used[{ticket[0],ticket[1]}]++;
    }

    for(auto& [key , destination] : graph)
    {
        sort(destination.begin(),destination.end());
    }

    path.push_back("ICN");
    dfs(graph,used,path,tickets.size());

    return path;
}

 

 

추가 알게 된 내용

 

1. 직관적인 자료구조 표현법

 

- 특정 도시를 시작으로 하는 티켓들을 나열하는 방법

- 구현 방법: unorderded_map<string,vector<string>>

- 구현 개념: [시작도시][도착도시1,도착도시2]... 로써의 표현 

 

2. 컨테이너 내부 값을 변경해야 할 경우 (& 키워드 사용)

 

for( : )문 사용시, 컨테이너의 내부값은 복사되어진다. 따라서 복사된 값을 변경하여도 실제 컨테이너 내부 값은 변경되지 않는다. 따라서 컨테이너 내부값을 변경하기 위해선 & 키워드를 추가하여 참조하도록 변경해야한다.