티스토리 뷰

알고리즘/백준

백준 2668 숫자고르기 C++

4567은 소수 2022. 3. 15. 01:18

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

 

2668번: 숫자고르기

세로 두 줄, 가로로 N개의 칸으로 이루어진 표가 있다. 첫째 줄의 각 칸에는 정수 1, 2, …, N이 차례대로 들어 있고 둘째 줄의 각 칸에는 1이상 N이하인 정수가 들어 있다. 첫째 줄에서 숫자를 적절

www.acmicpc.net

주어진 입력을 그래프로 생각하여 SCC를 이용해 풀었습니다.

 

1,2,3,4,5,6,7

3,1,1,5,5,4,6 과 같은 입력일 때

 

기존 그래프를

1->3 / 2->1 / 3->1 / 4->5 / 5->5 / 6->4 / 7->6 과 같이 생각할 수 있고, 이 때 permutation을 형성하게 된다면 강연결요소 중 하나이고 이러한 것들을 다 뽑는다면 정답에서 원하는 최대의 경우입니다.

 

단 자기 자신을 가리킬 수도 있으므로 SCC를 확인할 때 원소가 1개여도 자기 자신을 가리키는지 확인합니다.

 

코드는 다음과 같습니다.

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <stack>

using namespace std;

int n;
vector<int>graph[101]; // 주어진 그래프
vector<int>inv_graph[101]; // 역방향 그래프
bool visited[101]; // SCC 돌면서 노드 체크용
stack<int>stk; // SCC에 필요한 스택
vector<int>result; 

// 주어진 입력이 1->a, 2->b, ... 순의 그래프로 생각
// SCC 이용해서 강연결 요소인 것들 전부 골라내면 최대로 뽑은 것

void init()
{
	cin >> n;
	int node;
	for (int i = 1; i <= n; i++) {
		cin >> node;
		graph[i].push_back(node);
		inv_graph[node].push_back(i);
	}

	memset(visited, false, sizeof(visited));

	// 연결 요소 오름차순
	for (int i = 1; i <= n; i++) {
		sort(graph[i].begin(), graph[i].end());
		sort(inv_graph[i].begin(), inv_graph[i].end());
	}
}

void dfs(int node)
{
	// dfs로 연결된 애들 탐색
	// 끝나는 순으로 스택에 넣기
	// node : 시작 정점

	visited[node] = true;

	for (auto next_node : graph[node]) {
		if (visited[next_node])
			continue;
		dfs(next_node);
	}
	stk.push(node);
}

void dfs_inv(int node, vector<int>& vec)
{
	// 스택 top부터 역방향 그래프에서 dfs 

	visited[node] = true;
	vec.push_back(node);

	for (auto next_node : inv_graph[node]) {
		if (visited[next_node])
			continue;
		dfs_inv(next_node, vec);
	}
}

void SCC()
{
	// 코사라주 알고리즘으로 SCC 구하기

	for (int node = 1; node <= n; node++) {
		if (visited[node])
			continue;
		dfs(node);
	}

	memset(visited, false, sizeof(visited));
	vector<int>vec; // 강연결요소 저장용

	while (!stk.empty()) {
		int start = stk.top();
		stk.pop();

		if (visited[start])
			continue;

		dfs_inv(start, vec);

		// vec 확인
		// 원소 2개 이상이면 scc
		// 1개인데 자기 자신 가리켜도 scc

		if (vec.size() >= 2) {
			for (auto num : vec) {
				result.push_back(num);
			}
		}
		if (vec.size() == 1) {
			int num = vec[0];
			if (graph[num][0] == num)
				result.push_back(num); // graph는 값 1개만 가짐
		}

		vec.clear();
	}

	// 결과는 오름차순
	sort(result.begin(), result.end());
}

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

	init();
	SCC();

	cout << result.size() << '\n';

	for (auto num : result) {
		cout << num << '\n';
	}
}

 

'알고리즘 > 백준' 카테고리의 다른 글

백준 3955 캔디 분배 C++  (0) 2022.03.29
백준 16946 벽 부수고 이동하기 4 C++  (0) 2022.03.18
백준 1067 이동 C++  (0) 2022.03.05
백준 13277 큰 수 곱셈 C++  (1) 2022.03.05
백준 1708 볼록 껍질  (0) 2022.03.04
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
TAG
more
«   2025/02   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28
글 보관함