[소프티어] 출퇴근길 (C++)

우리누리·2023년 12월 18일
0

👓 문제 설명


자동차로 출퇴근을 하는 동환이는 지루하지 않게 종종 길을 바꿔 다니곤 한다. 새로운 동네를 발견하는 일은 동환이의 소소한 행복이다.


동환이의 출근길과 퇴근길은 가끔 겹친다. 즉, 출근길에 들른 동네를 퇴근길에 다시 지나곤 하는 것이다. 이에 대해 곰곰이 생각하던 동환이는 이렇게 두 번 들를 수 있는 동네가 그렇게 많지 않음을 깨달았다. 도로의 연결 모양, 그리고 일방통행 여부 등으로 인해 출퇴근길 모두 방문 가능한 동네가 한정되는 것이다.


동환이의 출퇴근길은 단방향 그래프로 나타낼 수 있다. 즉, 각 동네를 1부터 n까지의 번호가 매겨진 n개의 정점으로, m개의 일방통행의 도로를 단방향 간선으로 삼아 그래프를 만들 수 있다. 이때 동환이의 집과 회사가 각각 정점 S와 T로 나타난다고 하면 출퇴근길은 S와 T 사이의 경로로 나타난다.


동환이의 출퇴근길을 본딴 그래프가 주어지면 S에서 T로 가는 출근길 경로와 T에서 S로 가는 퇴근길 경로에 모두 포함될 수 있는 정점의 개수를 세는 프로그램을 작성하시오.


단, 출퇴근길에서 목적지 정점을 방문하고 나면 동환이는 더 이상 움직이지 않는다. 즉, 출근길 경로에 T는 마지막에 정확히 한 번만 등장하며, 퇴근길 경로도 마찬가지로 S는 마지막에 한 번만 등장해야 한다. (출근길 경로에 S는 여러 번 등장해도 되고, 퇴근길 경로에 T는 여러 번 등장해도 된다.)


💣 제한 사항

  • 5 ≤ n ≤ 100,000

  • 5 ≤ m ≤ 200,000

  • 1 ≤ S ≤ n이고 1 ≤ T ≤ n이며 S ≠ T

  • S에서 T로 가는 경로와 T에서 S로 가는 경로가 하나 이상 존재함이 보장된다.

  • 간선의 양 끝 점은 서로 다르다.

  • 같은 정점쌍을 같은 방향으로 잇는 간선은 두 개 이상 주어지지 않는다.


🚨 접근 방법

크게 4개의 조건을 생각하였다.
1. S->T 이동시 방문 노드
2. T->S 이동시 방문 노드
3. S->노드->S, S에서 다시 S로 돌아올 수 있는 노드
4. T->노드->T, T에서 다시 T로 돌아올 수 있는 노드

3,4의 경우 역방향 그래프를 별도로 생성하여 판단하였다.
출근길, 퇴근길의 경로에서 모두 방문하는 노드는 결국 양방향으로 이루어져있어야 한다.
이를 역방향 그래프를 통해 해결할 수 있다.


🚈 풀이

#include<iostream>
#include<vector>

using namespace std;

vector<int>v1[100001];
vector<int>v2[100001];
bool visited1[100001];
bool visited2[100001];
bool visited3[100001];
bool visited4[100001];

// 1. S->T 진행시 방문 노드
// 2. T->S 진행시 방문 노드
// 3. S에서 출발하여 S로 다시 돌아올 수 있는 노드
// 4. T에서 출발하여 T로 다시 돌아올 수 있는 노드 
// 3,4 상황에서 역방향 그래프를 이용하여 판별 가능 

void dfs(int cur,bool visited[],vector<int>v[]){
  if(visited[cur])return;
  visited[cur]=true;
  for(auto next:v[cur]){
    dfs(next,visited,v);
  }
}

int main(int argc, char** argv)
{
  int n,m,x,y,s,e,answer=0;
  cin>>n>>m;
  for(int i=0;i<m;i++){
    cin>>x>>y;
    v1[x].push_back(y);
    v2[y].push_back(x);
  }
  cin>>s>>e;

  // 출근길에는 e를 1번만 방문, 퇴근길에는 s를 한번만 방문
  visited1[e]=true;
  visited2[s]=true;
  dfs(s,visited1,v1);
  dfs(e,visited2,v1);
  dfs(s,visited3,v2);
  dfs(e,visited4,v2);
  for(int i=1;i<=n;i++){
    if(visited1[i]&&visited2[i]&&visited3[i]&&visited4[i])answer++;
  }
  cout<<answer-2;
   return 0;
}

0개의 댓글