Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

50-9kyo-hwang #181

Merged
merged 6 commits into from
Jun 30, 2024
Merged

50-9kyo-hwang #181

merged 6 commits into from
Jun 30, 2024

Conversation

9kyo-hwang
Copy link
Collaborator

@9kyo-hwang 9kyo-hwang commented May 27, 2024

πŸ”— 문제 링크

26146 즉ν₯ μ—¬ν–‰ (Easy)

βœ”οΈ μ†Œμš”λœ μ‹œκ°„

30λΆ„

✨ μˆ˜λ„ μ½”λ“œ

1. 문제

N개의 λ…Έλ“œμ™€ M개의 μ—£μ§€λ‘œ 이루어진 λ°©ν–₯ κ·Έλž˜ν”„κ°€ μ‘΄μž¬ν•œλ‹€.
μ–΄λ–€ λ…Έλ“œμ—μ„œ μΆœλ°œν•˜λ“ μ§€, λ‹€λ₯Έ λͺ¨λ“  λ…Έλ“œλ‘œ 갈 수 μžˆλŠ”μ§€ κ²€μ‚¬ν•˜λΌ.

쑰건

  • $1 \le N \le 200,000$
  • $1 \le M \le 500,000$

μ˜ˆμ‹œ 1

4 5  // N = 4, M = 5
1 2  // M개의 쀄에 걸쳐 엣지 정보가 주어짐
2 3  // 좜발 λ…Έλ“œ, 도착 λ…Έλ“œ
3 1
1 4
4 1

image
무슨 μ‹œμž‘μ μ„ μ„ νƒν•˜λ“  λͺ¨λ“  정점을 λ°©λ¬Έν•  수 μžˆλŠ” 경둜λ₯Ό 찾을 수 μžˆμœΌλ―€λ‘œ, 닡은 Yesκ°€ λœλ‹€. μ•„λž˜λŠ” κ°€λŠ₯ν•œ 경둜 쀑 ν•˜λ‚˜μ΄λ‹€.

  • 1 β†’ 4 β†’ 1 β†’ 2 β†’ 3
  • 2 β†’ 3 β†’ 1 β†’ 4
  • 3 β†’ 1 β†’ 2 β†’ 3 β†’ 1 β†’ 4
  • 4 β†’ 1 β†’ 4 β†’ 1 β†’ 2 β†’ 3 β†’ 1

μ˜ˆμ‹œ 2

4 4
1 2
2 3
3 4
4 2

image
1번 μ •μ μ—μ„œ μΆœλ°œν•˜λ©΄ λͺ¨λ“  정점을 λ°©λ¬Έν•  수 μžˆλŠ” κ²½λ‘œκ°€ μ‘΄μž¬ν•˜μ§€λ§Œ, 2번 μ •μ μ—μ„œ μΆœλ°œν•˜λ©΄ λͺ¨λ“  정점을 λ°©λ¬Έν•  수 μžˆλŠ” κ²½λ‘œκ°€ μ‘΄μž¬ν•˜μ§€ μ•ŠμœΌλ―€λ‘œ, 닡은 Noκ°€ λœλ‹€.

2. 풀이

μ˜† λ™λ„€μ—μ„œ "κ°•μ—°κ²° κ·Έλž˜ν”„"에 κ΄€ν•œ PR을 μž‘μ„±ν–ˆλŠ”λ°, 이λ₯Ό 보고 μ˜ˆμ „μ— μ•Œκ³ λ¦¬μ¦˜ 기말고사 μ‹œν—˜μ— λ‚˜μ™”λ˜ λ‚΄μš©μ΄ λ– μ˜¬λžλ‹€.

image

  • 22λ…„ 1ν•™κΈ° ꢌ κ΅μˆ˜λ‹˜ μ•Œκ³ λ¦¬μ¦˜ 기말고사 문제 :)

μœ„ μ΄λ―Έμ§€μ—μ„œ 적힌 μ„€λͺ…λŒ€λ‘œ, κ°•μ—°κ²° κ·Έλž˜ν”„μΈμ§€ ν™•μΈν•˜λŠ” 방법은 μ•„λž˜μ™€ κ°™λ‹€.

  1. 주어진 κ·Έλž˜ν”„ $G$에 λŒ€ν•΄, μž„μ˜μ˜ 정점 uμ—μ„œ μΆœλ°œν•˜λŠ” BFS/DFSλ₯Ό μˆ˜ν–‰ν•΄ λ‹€λ₯Έ λͺ¨λ“  정점에 도달할 수 μžˆλŠ” 지 검사
  2. 주어진 κ·Έλž˜ν”„ $G$μ—μ„œ λͺ¨λ“  μ—£μ§€λ“€μ˜ λ°©ν–₯을 뒀집은 $G^C$λ₯Ό λ§Œλ“  λ’€ λ™μΌν•œ μž„μ˜μ˜ 정점 uμ—μ„œ μΆœλ°œν•˜λŠ” BFS/DFSλ₯Ό μˆ˜ν–‰ν•΄ λ‹€λ₯Έ λͺ¨λ“  정점에 도달할 수 μžˆλŠ” 지 검사
  3. 1, 2번이 λͺ¨λ‘ κ°€λŠ₯ν•˜λ‹€λ©΄ κ°•μ—°κ²° κ·Έλž˜ν”„

이λ₯Ό ν† λŒ€λ‘œ μ½”λ“œλ₯Ό μž‘μ„±ν•œλ‹€.

int main()
{
    cin.tie(nullptr)->sync_with_stdio(false);
    
    int N, M; cin >> N >> M;  
    
    vector<vector<int>> G(N + 1);
    vector<vector<int>> GC(N + 1);
    
    while(M--)
    {
        int v, w; cin >> v >> w;
        G[v].emplace_back(w);
        GC[w].emplace_back(v);
    }
    
    cout << (DFS(N, G) && DFS(N, GC) ? "Yes" : "No");

    return 0;
}

μž…λ ₯으둜 엣지듀이 μ£Όμ–΄μ§ˆ λ•Œ, μ •λ°©ν–₯ κ·Έλž˜ν”„ $G$와 μ—­λ°©ν–₯ κ·Έλž˜ν”„ $G^C$λ₯Ό κ΅¬μΆ•ν•œλ‹€.
DFS ν•¨μˆ˜λ₯Ό 두 κ·Έλž˜ν”„μ— λŒ€ν•΄ ν˜ΈμΆœν•΄ λͺ¨λ‘ Trueκ°€ λ°˜ν™˜λλ‹€λ©΄ "Yes"λ₯Ό 좜λ ₯ν•˜κ³ , ν•˜λ‚˜λΌλ„ Falseκ°€ λ°˜ν™˜λλ‹€λ©΄ "No"λ₯Ό 좜λ ₯ν•œλ‹€.

bool DFS(const int N, vector<vector<int>>& Graph)
{
    vector<bool> Visited(N + 1, false);
    DFSHelper(Graph, Visited);
    
    for(int Node = 1; Node <= N; ++Node)
    {
        if(!Visited[Node])
        {
            return false;
        }
    }
    return true;
}

DFS ν•¨μˆ˜λŠ” λ°©λ¬Έ 체크λ₯Ό ν™•μΈν•˜λŠ” Visited 리슀트λ₯Ό μƒμ„±ν•œλ’€, μ‹€μ§ˆμ μœΌλ‘œ DFSλ₯Ό μˆ˜ν–‰ν•˜λŠ” DFSHelper ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•˜λŠ” 역할을 λ‹΄λ‹Ήν•œλ‹€.
DFSHelper ν•¨μˆ˜λ₯Ό μˆ˜ν–‰ν•œ λ’€ Visited 리슀트λ₯Ό μˆœνšŒν•΄ ν•˜λ‚˜λΌλ„ λ„λ‹¬ν•˜μ§€ λͺ»ν•œ λ…Έλ“œκ°€ μ‘΄μž¬ν•˜λŠ” return false, μ•„λ‹ˆλΌλ©΄ return trueλ₯Ό λ°˜ν™˜ν•œλ‹€.

void DFSHelper(const vector<vector<int>>& Graph, vector<bool>& Visited, int SrcNode = 1)
{
    Visited[SrcNode] = true;
    for(const auto& DstNode : Graph[SrcNode])
    {
        if(!Visited[DstNode])
        {
            DFSHelper(Graph, Visited, DstNode);
        }
    }
}

DFSHelper ν•¨μˆ˜λŠ” μ „ν˜•μ μΈ DFS 순회 ν•¨μˆ˜μ΄λ‹€. "μž„μ˜μ˜ λ…Έλ“œ"에 λŒ€ν•΄ μΆœλ°œν•˜λ©΄ λ˜λ―€λ‘œ 졜초 좜발 λ…Έλ“œλ₯Ό 1번으둜 μ§€μ •ν•œλ‹€.

이 μ•Œκ³ λ¦¬μ¦˜μ€ 2번의 DFS만 μˆ˜ν–‰ν•˜λ©΄ λ˜λ―€λ‘œ μ‹œκ°„ λ³΅μž‘λ„λŠ” $O(2 * (N + M)) = O(N + M)$이닀.

전체 μ½”λ“œ

#include <iostream>
#include <vector>

using namespace std;

void DFSHelper(const vector<vector<int>>& Graph, vector<bool>& Visited, int SrcNode = 1)
{
    Visited[SrcNode] = true;
    for(const auto& DstNode : Graph[SrcNode])
    {
        if(!Visited[DstNode])
        {
            DFSHelper(Graph, Visited, DstNode);
        }
    }
}

bool DFS(const int N, vector<vector<int>>& Graph)
{
    vector<bool> Visited(N + 1, false);
    DFSHelper(Graph, Visited);
    
    for(int Node = 1; Node <= N; ++Node)
    {
        if(!Visited[Node])
        {
            return false;
        }
    }
    return true;
}

int main()
{
    cin.tie(nullptr)->sync_with_stdio(false);
    
    int N, M; cin >> N >> M;
    
    vector<vector<int>> G(N + 1);
    vector<vector<int>> GC(N + 1);
    
    while(M--)
    {
        int v, w; cin >> v >> w;
        G[v].emplace_back(w);
        GC[w].emplace_back(v);
    }
    
    cout << (DFS(N, G) && DFS(N, GC) ? "Yes" : "No");

    return 0;
}

πŸ“š μƒˆλ‘­κ²Œ μ•Œκ²Œλœ λ‚΄μš©

사싀 이 λ‚΄μš©μ€ SCC(Strongly Connected Component, κ°•ν•œ μ—°κ²° μš”μ†Œ) 에 λŒ€ν•œ 특수 μΌ€μ΄μŠ€μ΄λ‹€.
일반적으둜 κ·Έλž˜ν”„ λ‚΄ μ—¬λŸ¬ 개의 SCCλ₯Ό μΆ”μΆœν•˜λŠ” ν˜•μ‹μΈλ°, 이 λ¬Έμ œλŠ” 전체 κ·Έλž˜ν”„μ— λŒ€ν•΄ SCCκ°€ ν•˜λ‚˜λ§Œ μ‘΄μž¬ν•˜λŠ” κ²½μš°μ΄λ‹€.

SCCλ₯Ό μΆ”μΆœν•˜λŠ” λŒ€ν‘œμ μΈ μ•Œκ³ λ¦¬μ¦˜ 2가지가 "코사라주 μ•Œκ³ λ¦¬μ¦˜"κ³Ό "νƒ€μž” μ•Œκ³ λ¦¬μ¦˜"인데, μ—¬κΈ°μ„œ μ‚¬μš©λœ μ•Œκ³ λ¦¬μ¦˜μ΄ "코사라주 μ•Œκ³ λ¦¬μ¦˜"κ³Ό 거의 λ™μΌν•˜λ‹€.

λ§Œμ•½ 이 μ•Œκ³ λ¦¬μ¦˜μ„ μ‚¬μš©ν•˜μ§€ μ•ŠλŠ”λ‹€λ©΄ "λͺ¨λ“  λ…Έλ“œμ— λŒ€ν•΄" ν•œ λ²ˆμ”© BFS/DFSλ₯Ό μˆ˜ν–‰ν•΄μ•Ό ν•˜λŠ”λ°, μ΄λŠ” $O(N * (N + M))$ μ‹œκ°„λ³΅μž‘λ„κ°€ κ±Έλ € μ΅œμ•…μ˜ 경우 1400μ–΅λ²ˆμ˜ 연산이 ν•„μš”ν•΄ μ‹œκ°„μ΄ μ΄ˆκ³Όν•œλ‹€.

Copy link
Collaborator

@mjj111 mjj111 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nκ³Ό M이 λ„ˆλ¬΄ ν¬λ‹€λ³΄λ‹ˆ ,O(NM) O(N**2)... μ΄μƒμœΌλ‘œλŠ” ν•΄κ²°ν•  수 μ—†μ–΄λ³΄μ˜€μŠ΅λ‹ˆλ‹€..
κ·Έλž˜μ„œ N +M 으둜 순회λ₯Ό ν•œ 번 ν•˜κ³ μ„œ 흔적을 남겨,
각 λ…Έλ“œκ°€ μ–΄λ””κΉŒμ§€ 접근이 κ°€λŠ₯ν•œμ§€λ₯Ό 기둝해주면 μ–΄λ–¨κΉŒλž€ 아이디어λ₯Ό λ– μ˜¬λ Έμ–΄μš”.

그런데.. 루프가 μžˆμ„ κ²½μš°μ— λŒ€ν•΄μ„œ μœ„ 과정은 λΆˆκ°€ν•˜λ”κ΅°μš” 😒(20λΆ„ 헛짓)
결ꡭ에 κ΅ν™©λ‹˜κ»˜μ„œ μ°Έκ³ ν•΄μ£Όμ‹  κ°•μ—°κ²°κ·Έλž˜ν”„ κ΄€λ ¨ λ‚΄μš© 읽고 겨우 ν’€μ—ˆλ„€μš” γ… 

λ„ˆλ¬΄ 쒋은 문제..! κ³ μƒν•˜μ…¨μŠ΅λ‹ˆλ‹€πŸ‘

public class Main {

    static boolean[] visited;
    static Stack<Integer> stack = new Stack<>();

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        int v = Integer.parseInt(st.nextToken());
        int e = Integer.parseInt(st.nextToken());

        visited = new boolean[v + 1];
        List<Integer>[] graph = new ArrayList[v + 1];
        List<Integer>[] reverseGraph = new ArrayList[v + 1];

        for(int i = 1; i <= v; i++) {
            graph[i] = new ArrayList<>();
            reverseGraph[i] = new ArrayList<>();
        }

        for(int i = 0; i < e; i++) {
            st = new StringTokenizer(br.readLine());
            int from = Integer.parseInt(st.nextToken());
            int to = Integer.parseInt(st.nextToken());

            graph[from].add(to);
            reverseGraph[to].add(from);
        }

        for(int i = 1; i <= v; i++) {
            if(!visited[i]) {
                dfs(i, graph, false);
            }	//λ°©λ¬Έ ν•˜μ§€ μ•Šμ•˜λ‹€λ©΄ dfs둜 λ°©λ¬Έ
        }

        visited = new boolean[v + 1];
        dfs(stack.pop(), reverseGraph, true);

        String answer = "Yes";
        while(!stack.isEmpty()) {
            // μŠ€νƒμ΄ λΉ„μ–΄μžˆμ„λ•ŒκΉŒμ§€ κΊΌλ‚΄λŠ”λ°, λ°©λ¬Έν•˜μ§€ μ•Šμ•˜λ‹€λ©΄ λͺ¨λ‘ μ—°κ²°λ˜μ–΄ μžˆμ§€ μ•ŠμœΌλ―€λ‘œ No
            if(!visited[stack.pop()]) {
                answer = "No";
                break;
            }
        }

        System.out.print(answer);
    }

    public static void dfs(int depth, List<Integer>[] graph, boolean isReverseGraph) {
        visited[depth] = true;

        for(int a : graph[depth]) {
            if(!visited[a]) {
                dfs(a, graph, isReverseGraph);
            }
        }

        // μ •λ°©ν–₯ κ·Έλž˜ν”„μΌ κ²½μš°μ—λ§Œ stack에 μ €μž₯
        if(!isReverseGraph) {
            stack.add(depth);
        }
    }
}

Copy link
Member

@xxubin04 xxubin04 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SCC..! μ—„μ²­ μžμ„Έν•˜κ²Œ 써주신 μ„€λͺ… 덕뢄에 μ‰½κ²Œ μ΄ν•΄ν•˜κ³  κ°‘λ‹ˆλ‹€!
μ•žμœΌλ‘œ μ‹œμž‘μ μ΄ 주어지지 μ•Šκ³  μ–΄λ–»κ²Œλ“  λͺ¨λ“  λ…Έλ“œλ₯Ό λ°©λ¬Έν•  수 μžˆλŠ”μ§€λ₯Ό λ¬»λŠ” λ¬Έμ œκ°€ λ‚˜μ˜€λ©΄, κ°•μ—°κ²° κ·Έλž˜ν”„λ₯Ό λ– μ˜¬λ¦¬λ©΄ λ˜κ² κ΅°μš”!

문제λ₯Ό λ„μ „ν•΄λ³΄μ•˜λŠ”λ° μ‹œκ°„μ΄ˆκ³Όκ°€ μ—„μ²­λ‚˜κ²Œ λ‚¬μŠ΅λ‹ˆλ‹€..
κ·Έλž˜μ„œ 코사라주 μ•Œκ³ λ¦¬μ¦˜μœΌλ‘œ λ‹€μ‹œ 풀어보렀닀 μ‹œκ°„μ΄ 였래 걸릴 것 κ°™μ•„ μš°μ„  리뷰 κΈ‰ν•˜κ²Œ λ‚¨κΉλ‹ˆλ‹€!!
μ‹œκ°„μ΄ˆκ³Όλ‚¬μ§€λ§Œ μš°μ„  μ˜¬λ¦¬λ„λ‘ ν•˜κ² μŠ΅λ‹ˆλ‹€πŸ€―

μ‹œκ°„μ΄ˆκ³Ό λ‚œ μ½”λ“œ...
from collections import deque
import sys
sys.setrecursionlimit(10**6)
input = open(0).readline

nation_num, flight_num = map(int, input().split())
forward_graph = [[] for _ in range(nation_num + 1)]
reverse_graph = [[] for _ in range(nation_num + 1)]

for i in range(flight_num):
    n, m = map(int, input().split())
    forward_graph[n].append(m)
    reverse_graph[m].append(n)

def DFS(q, visited, graph):
    while q:
        x = q.popleft()

        if not visited[x]:
            visited[x] = 1
            for node in graph[x]:
                q.append(node)
            DFS(q, visited, graph)

for k in range(1, nation_num+1):
    q_f, q_r = deque([k]), deque([k])
    visited_f = [1] + [0 for _ in range(nation_num)]
    visited_r = [1] + [0 for _ in range(nation_num)]
    DFS(q_f, visited_f, forward_graph)
    DFS(q_r, visited_r, reverse_graph)

    if sum(visited_f) == nation_num+1 and sum(visited_r) == nation_num+1:
        print("Yes")
        break

    elif k == nation_num and(sum(visited_f) != nation_num or sum(visited_r) != nation_num):
        print("No")

Copy link
Member

@gjsk132 gjsk132 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

λ‚˜λ¦„ μŒˆλΉ‘ν•œ 풀이λ₯Ό 생각은 ν–ˆμ§€λ§Œ... κ΅¬ν˜„ λ‹¨κ³„μ—μ„œ ν¬κΈ°ν–ˆμŠ΅λ‹ˆλ‹€.

  1. 1번 μ§€μ μ—μ„œ μ‹œμž‘ν•΄μ„œ, λͺ¨λ“  κ²½λ‘œμ— λŒ€ν•΄ λ‹€μ‹œ 1번 μ§€μ μœΌλ‘œ λŒμ•„μ˜¬ 수 μžˆλ‹€.
  2. μœ„ κ³Όμ •μ—μ„œ λͺ¨λ“  λ…Έλ“œλ₯Ό 지났닀.

μœ„μ— 2가지가 λœλ‹€λ©΄, Yesλ₯Ό 좜λ ₯ν•œλ‹€! 라고 ν•˜κ³  μ‹Άμ—ˆμ§€λ§Œ...
μ½”λ“œ μ§œκΈ°μ— μ‹€νŒ¨ν•˜κ³ , μ–΄μ°Œμ €μ°Œ 일단 μ œμΆœν–ˆλŠ”λ°, μ‹œκ°„ μ΄ˆκ³ΌλΌλŠ” κ²°κ³Όκ°€...γ…œγ… 
이게 μ™œ μ‹œκ°„ 초과 λ‚˜μ§€

SCCλΌλ‹ˆ... μš”μ¦˜ ν•˜λ©΄ ν• μˆ˜λ‘ 아직 λͺ» λ“€μ–΄λ³Έ μ•Œκ³ λ¦¬μ¦˜λ„ μ—„μ²­ 많이 λ‚¨μ•˜λ‹€λŠ”κ±Έ κΉ¨λ‹«μŠ΅λ‹ˆλ‹€...

γ…Ž...ν•œ μ‹œκ°„λ§Œ 더 이 λ¬Έμ œμ— νˆ¬μžν•΄λ³Όκ²Œμš”

@9kyo-hwang 9kyo-hwang merged commit 2eefd97 into main Jun 30, 2024
7 checks passed
@9kyo-hwang 9kyo-hwang deleted the 50-9kyo-hwang branch June 30, 2024 16:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants