풀이 보관함

[C++] 백준 9466번: 텀 프로젝트 본문

problem solving/백준

[C++] 백준 9466번: 텀 프로젝트

viin 2022. 8. 20. 21:43

문제

https://www.acmicpc.net/problem/9466

 

9466번: 텀 프로젝트

이번 가을학기에 '문제 해결' 강의를 신청한 학생들은 텀 프로젝트를 수행해야 한다. 프로젝트 팀원 수에는 제한이 없다. 심지어 모든 학생들이 동일한 팀의 팀원인 경우와 같이 한 팀만 있을

www.acmicpc.net

 

풀이 과정

 

싸이클이 형성되면 팀이 생성된다.


싸이클이 형성되는 경우

 

1) 첫번째 노드와 마지막 노드가 같을 경우

 

4 - 7 - 6 - 4

 

2) n번째 노드와 미지막 노드가 같을 경우

 

2 - 1 - 3 - 3

 

 

🚩 반드시 알아야 할 것

  • 재방문으로 사이클 형성을 알 수 있다.
  • 재방문 노드 이전의 노드들 (경로)은 사이클 형성 불가한 노드라는게 판정된다.
    • 첫번째 노드를 1, 2, 3 .. 로 진행하다가 5 - 6 - 1 - 2- 1 를 진행하게 됐다.
    • 6 - 1 - 2 - 1 를 탐색했으니까.
    • 5, 6은 사이클 형성 불가다.
    • 6을 첫번째 노드로 탐색하지 않아도 된다.

      이렇게  각 노드를 한번씩 방문하여 시간 초과가 나지 않도록 신경 써야 한다. O(n)

 

소스 

 

경로를 저장하기 위해 queue를 사용했다.

  • teamed은 팀 형성 여부 저정용
  • visited는 재방문으로 싸이클 판단용

 

? 탐색을 하다가 중간에 이미 탐색하면서 사이클 못만든다고 나온 노드가 나온다면?
queue에 저장하고 있던 경로들도 사이클을 못 만든다고 표시 해준다.

 

? 탐색하다가 이미 팀을 만든 친구들이 나온다면?

지금 노드도 포함해서 만들 수 있는지 모르겠으니까 걍 경로를 싹 지워준다..

 

? 팀 형성 판단도 안된 노드인데 재방문이다?

재방문 노드부터 싸이클 형성 가능하다!

재방문 노드 이전은 사이클 형성 불가능이라고 표시해주고 큐에서 날려버린다. 

main문에서 queue에 남은 노드들만 사이클 가능 표시를 해준다. 

 

#include <iostream>
#include <queue>
#include <memory.h>
#define MAX 100001

bool visited[MAX+1];
int teamed[MAX+1];
int pick[MAX+1];
int N = 0;
std::queue<int> q;

void DFS(int i)
{
    int temp = 0;
    if(teamed[i] == -1)
    {
        while(!q.empty())
        {
            temp = q.front();
            teamed[temp] = -1; // team 구성 불가.
            q.pop();
        }
        return;
    }
    
    if(teamed[i] == 1)
    {
        while(!q.empty())
        {
            q.pop();
        }
        return;
    }
    
    if(visited[i])
    {
        while(!q.empty())
        {
            temp = q.front();
            if(temp == i)
                break;
            teamed[temp] = -1; // team 구성 불가.
            q.pop();
        }
        return;
    }
    
    q.push(i);
    visited[i] = true;
    DFS(pick[i]);
}

int main()
{
    int T=0; std::cin >> T;

    while(T--)
    {
        int result = 0;
        int temp = 0;
        std::cin >> N;
        memset(pick, 0, sizeof(pick));
        memset(teamed, 0, sizeof(teamed));
        memset(visited, false, sizeof(visited));

        //input
        for(int i=1; i<=N; ++i)
        {
            std::cin >> pick[i];
        }
        
        //solve
        for(int i=1; i<=N; ++i)
        {
            DFS(i);
            while(!q.empty())
            {
                temp = q.front(); q.pop();
                teamed[temp] = 1;
            }
        }
        
        //output
        for(int i=1; i<=N; ++i)
        {
            if(teamed[i]!=1)
                ++result;
        }
        std::cout << result <<'\n';
        
    }//T
    return 0;
}