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

31-yuna83 #145

Merged
merged 2 commits into from
Mar 4, 2024
Merged

31-yuna83 #145

merged 2 commits into from
Mar 4, 2024

Conversation

yuna83
Copy link
Member

@yuna83 yuna83 commented Feb 23, 2024

🔗 문제 링크

바이러스


✔️ 소요된 시간

40분


✨ 수도 코드

한 컴퓨터가 웜 바이러스에 걸리면 그 컴퓨터와 네트워크 상에서 연결되어 있는 모든 컴퓨터는 웜 바이러스에 걸리게 될 때,
1번 컴퓨터를 통해 웜 바이러스에 걸리게 되는 컴퓨터의 수를 출력!

ex) 입력
7 컴퓨터의 수
6 연결된 컴퓨터쌍의 수
1 2
2 3
1 5
5 2
5 6
4 7

이면 1-2-3,1-5-6으로 연결되기 때문에 1제외 4개의 컴퓨터가 감염되므로
4 출력

입력에서 주어진대로 그래프를 생성한 다음
1번 컴퓨터를 기준으로 DFS or BFS로 탐색하여
연결되어 있는 컴퓨터의 수를 세면 된다!!


1. 주어진 정보로 그래프를 생성한다.

N= int(input())
link = int(input())
network = [[]*(N+1) for _ in range(N+1)]
for i in range(link): # 네트워크 연결 정보 입력
    a, b = map(int, input().split())
    network[a].append(b) # 양방향 연결
    network[b].append(a)
visited = [0]*(N+1) # 방문 여부 저장

바이러스에 감염된 걸 방문했음으로 가정
연결된 컴퓨터는 감염되므로
그래프network를 탐색하면 된다!



2. 탐색하여 연결여부를 구한다.

DFS(재귀호출)

: 하나의 정점을 완전히 탐색!

def DFS(virus):
    global cnt
    visited[virus]=1
    for i in network[virus]:
        if (visited[i]==0):
            DFS(i)
            cnt+=1

시작 컴퓨터는 감염되어 있고 visited[virus]=1
연결되어 있는 컴퓨터를 탐색
바이러스에 걸리지 않았다면 if (visited[i]==0):
해당 컴퓨터를 기준으로 탐색을 다시한다!



BFS(큐, 반복문)

: 인접한 정점을 우선 탐색!

def BFS(virus):
    global cnt
    visited[virus] = 1
    queue = [virus]
    while queue:
        for i in network[queue.pop()]:
            if (visited[i]==0):
                visited[i]=1
                queue.insert(0, i)
                cnt+=1

큐를 만들어 시작 컴퓨터를 넣고
하나씩 꺼내어 연결된 컴퓨터를 탐색for i in network[queue.pop()]:
연결된 컴퓨터를 찾으면 큐에 넣어 다시 탐색!



3. 연결된 컴퓨터 수를 반환한다.

시작 컴퓨터는 1번으로 고정이므로
1번 컴퓨터를 기준으로 탐색을 실행하여 DFS(1)
cnt를 반환한다!



전체코드DFS

cnt=0
def DFS(virus):
    global cnt
    visited[virus]=1
    for i in network[virus]:
        if (visited[i]==0):
            DFS(i)
            cnt+=1

N= int(input())
link = int(input())
network = [[]*(N+1) for _ in range(N+1)]
for i in range(link):
    a, b = map(int, input().split())
    network[a].append(b)
    network[b].append(a)
visited = [0]*(N+1)
DFS(1)
print(cnt)


전체코드BFS

cnt=0
def BFS(virus):
    global cnt
    visited[virus] = 1
    queue = [virus]
    while queue:
        for i in network[queue.pop()]:
            if (visited[i]==0):
                visited[i]=1
                queue.insert(0, i)
                cnt+=1


N= int(input())
link = int(input())
network = [[]*(N+1) for _ in range(N+1)] # 네트워크 연결
for i in range(link):
    a, b = map(int, input().split())
    network[a].append(b)
    network[b].append(a)
visited = [0]*(N+1)
BFS(1)
print(cnt)


📚 새롭게 알게된 내용

오랜만에 BFS/DFS 문제 풀어봤는데
개념을 상기시키기 딱이었습니다!!

<도움받은 출처>
https://hyundoil.tistory.com/28


N= int(input())
link = int(input())

network = [[]*(N+1) for _ in range(N+1)]

Choose a reason for hiding this comment

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

network = [[]*(N+1) for _ in range(N+1)]

2차원 리스트 내에 1차원 리스트를 다시 (N + 1)개씩 만들어줄 필요는 없습니다.

network = [[] for _ in range(N+1)]

이걸로도 충분합니다. 어차피 append로 동적으로 늘려가기 때문이죠 :)

image 짜잔 똑같은 걸 알 수 있답니다.

Copy link
Member

Choose a reason for hiding this comment

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

사실 append하는 거라서 초기화 안시켜놔도 되긴 한데..

초기화 시켜놓는 것이 더 빠르다고 하더라고요 미리 메모리를 할당해놓는 거라서.

동적으로 할당하면 중간중간 메모리가 더 필요할 때 메모리 이동시키느라고 시간이 드는데 ..

(잡 지식)

Choose a reason for hiding this comment

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

�근데 append를 통해 동적으로 추가하는 것도 메모리 공간을 어느정도 여유를 주고 할당을 시작해서 일반적으로 PS 하는 정도의 데이터로는 시간 많이 안잡아먹을듯?
CPython 기준으로 포인터들의 배열로 list가 구현돼있어서 리스트 내 원소들을 몽땅 다 옮기는 과정도 많이 안일어나는 것 같고. how-is-pythons-list-implemented

아예 인접행렬 방식으로 틀어버리는 것도 한 방법일 듯.

Copy link
Member

@tgyuuAn tgyuuAn left a comment

Choose a reason for hiding this comment

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

누가봐도 명백한 BFS/DFS 문제지만

유니온 파인드로도 풀릴 것 같아서 요즘 공부하는 겸 유니온 파인드로도 풀어봤씁니다!

import sys

computers_count = int(sys.stdin.readline())
connections_count = int(sys.stdin.readline())

computers = [x for x in range(computers_count+1)]

def union_find(first, second, graph):
    x = find_parent(first, graph)
    y = find_parent(second, graph)

    x, y = max(x, y), min(x, y)
    graph[x] = y
    return

def find_parent(element, graph):
    if element == graph[element]: return element
    parent = find_parent(graph[element],graph)
    graph[element] = parent
    return parent

for _ in range(connections_count):
    start, destination = map(int,sys.stdin.readline().split())
    union_find(start,destination,computers)

if connections_count == 0: print(0)
else:
    answer = 0
    for parent_computer in computers:
        if find_parent(parent_computer, computers) == 1: answer += 1
        
    print(answer-1)

근데 뭐.. BFS로 푸는게 코드가 훨 짧을 것 같네요.. 허허..

유나님이랑 더 스터디를 진행하지 못해 너무 아쉬워요 ㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠ

4개월 동안 정말 고생하셨습니다! 🥲🥲

N= int(input())
link = int(input())

network = [[]*(N+1) for _ in range(N+1)]
Copy link
Member

Choose a reason for hiding this comment

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

사실 append하는 거라서 초기화 안시켜놔도 되긴 한데..

초기화 시켜놓는 것이 더 빠르다고 하더라고요 미리 메모리를 할당해놓는 거라서.

동적으로 할당하면 중간중간 메모리가 더 필요할 때 메모리 이동시키느라고 시간이 드는데 ..

(잡 지식)

@Munbin-Lee
Copy link
Member

Munbin-Lee commented Feb 27, 2024

Code
#include <iostream>
#include <vector>
#include <numeric>
#include <functional>

using namespace std;

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);

    int numComputer, numNetwork;
    cin >> numComputer >> numNetwork;

    vector<int> roots(numComputer + 1);
    iota(roots.begin(), roots.end(), 0);

    function<int(int)> find = [&](int x) {
        if (roots[x] == x) return x;

        return roots[x] = find(roots[x]);
    };

    auto merge = [&](int a, int b) {
        a = find(a);
        b = find(b);

        if (a < b) swap(a, b);

        roots[a] = b;
    };

    while (numNetwork--) {
        int c1, c2;
        cin >> c1 >> c2;

        merge(c1, c2);
    }

    int answer = 0;

    for (int i = 2; i <= numComputer; i++) {
        answer += (find(i) == 1);
    }

    cout << answer;

    return 0;
}

원래 유니온 파인드로 풀었다가, 태규님 코멘트 보고 백트래킹으로 풀어서 비교하려고 했으나 둘 다 0ms가 나와서 비교에 실패했습니다.

유나님 꽤 오랫동안 하셨는데 가신다니 아쉬워요😢

@@ -0,0 +1,21 @@
cnt=0
def DFS(virus):
global cnt
Copy link
Member

Choose a reason for hiding this comment

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

visited는 놔두고 cnt만 global 처리하셨는데 이유가 있나요?

Copy link
Member

Choose a reason for hiding this comment

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

문빈리 모각코 안오시나요!!!!!!!!!!?

Copy link
Member

Choose a reason for hiding this comment

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

그럼요.

@pknujsp
Copy link
Collaborator

pknujsp commented Feb 28, 2024

dfs, bfs 두 방법으로 풀어보셨군요
저는 bfs로 풀어봤습니다

근 네 달동안 스터디 하신다고 정말 고생 많으셨어요

벌써 이렇게 됐다니 아쉽네용
PR올라올 때 마다 실력이 느시는게 느껴졌었는데
많은 도움이 되셨을런지요

from sys import stdin
from collections import *

pc = int(stdin.readline())
edge_count = int(stdin.readline())
graph = defaultdict(list)

for _ in range(edge_count):
    l, f = map(int, stdin.readline().split())
    graph[l].append(f)
    graph[f].append(l)

q = deque([1])

died_pc = [False for _ in range(pc + 1)]
died_pc[1] = True

while q:
    p = q.popleft()
    if graph.get(p) is not None:
        for next_p in graph[p]:
            if not died_pc[next_p]:
                died_pc[next_p] = True
                q.append(next_p)

print(died_pc.count(True) - 1)

항상 파이팅입니다!!

@yuna83 yuna83 merged commit 7138d16 into AlgoLeadMe:main Mar 4, 2024
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.

5 participants