baekjoon

[백준] 10891 Cactus? Not cactus? -선인장그래프

윤만석 2023. 7. 3. 17:43

문제

선인장이란 양방향 그래프의 일종인데, 각 정점에 대해 자기 자신으로 돌아오는 경로(단순 사이클)가 하나 이하인 그래프이다. 주어진 그래프가 선인장일까? 아닐까?

입력

첫 번째 줄에 그래프의 정점의 개수와 간선의 개수를 나타내는 두 정수 N,M (1 ≤ N,M ≤ 100,000) 이 공백으로 구분되어 주어진다.

다음 M개의 줄에는 간선이 연결하고 있는 두 정점을 나타내는 두 정수 x,y (1 ≤ x,y ≤ N,x ≠ y)가 공백으로 구분되어 주어진다. 주어진 간선은 중복되지 않으며, 임의의 두 정점에 대해 경로가 존재한다.

출력

주어진 그래프가 선인장이면 "Cactus" 를 아니라면 "Not cactus" 를 출력한다.

 

선인장 그래프 문제입니다.

단순 사이클이란 한 사이클에서 같은 정점을 방문하지 않는 사이클입니다.

 

BCC로 간선을 묶으면 쉽게 해결할 수 있습니다.

1.

두개 이상의 BCC에 한 정점이 겹치게 된다면 이 그래프는 선인장이 아닙니다.

  그 정점에서 사이클이 두개 이상 생기기 때문입니다.

 

2.

만약 한 BCC안에 정점이 두개만 존재하면, 선인장입니다. 

그러나

만약 한 BCC안에 정점이 세개 이상일때, 간선의 개수가 정점의 개수보다 많다면,

그 BCC안에서는 단순사이클이 두개이상 생길 수 있습니다.

따라서 한 BCC안에는 정점의 개수와 간선의 개수가 같아야 합니다.

 

#include<bits/stdc++.h>
#define FAST ios_base::sync_with_stdio(false),cin.tie(NULL);
#define mset(v) memset(v,0,sizeof(v));
#define rep(i,a) for(int i=0;i<a;++i)
#define REP(i,a) for(int i=1;i<=a;++i)

using namespace std;

typedef long long ll;
typedef pair<int, int> pi;
typedef tuple<int, int, int>ti;
typedef vector<int> vi;
typedef vector<vector<int>> vvi;
int dy[] = { -1,0,1,0 }, dx[] = { 0,1,0,-1 }, INF = 987654321;
int V, E, dfsn[100001], cnt;
stack<pi>st;
vi adj[100001];
vvi bcc;
vector<pi>bc;
//pre는 부모노드를 의미합니다.
int dfs(int k, int pre = -1) {

	//result는 도달가능한 정점의 최소 dfsn을 저장합니다.
	int result = dfsn[k] = ++cnt;

	//모든 도달가능한 정점에대해
	for (int next : adj[k]) {

		//부모노드라면 생략
		if (next == pre)continue;

		//만약 처음 방문하는 간선이라면 stack에 Push
		if (dfsn[k] > dfsn[next])st.push(pi{ k,next });

		//이미 방문한 정점이라면, dfsn값을 비교하여 result에 작은값을 저장합니다
		if (dfsn[next] > 0)result = min(result, dfsn[next]);

		//처음 방문한 정점이라면 dfs로 진행합니다
		else {

			//result와 자식정점의 dfsn와 비교해 작은값을 저장합니다.
			int temp = dfs(next, k);
			result = min(result, temp);

			//만약 현재 dfsn과 자식 dfsn을 비교했을때, 현재값이 크거나 같으면
			//현재노드의 부모노드로는 더이상 갈 수 없음을 의미합니다. BCC를 발견했습니다.
			//현재노드까지 BCC입니다.
			if (temp >= dfsn[k]) {

				vi vt;
				while (!st.empty()) {
					pi top = st.top();
					st.pop();
					vt.push_back(top.first);
					vt.push_back(top.second);
					if (top == pi{ k,next })break;
				}
				bcc.push_back(vt);
			}
		}
	}
	return result;
}
int main() {
	FAST;
	cin >> V >> E;
	rep(i, E) {
		int a, b;
		cin >> a >> b;
		adj[a].push_back(b);
		adj[b].push_back(a);
	}
	REP(i, V) {
		if (!dfsn[i])dfs(i);
	}
	int v[100001];
	mset(v);
    //모든 bcc에 대해서
	for (auto r : bcc) { 
    	//간선의 수
		int edges = r.size() / 2;
		sort(r.begin(), r.end());
		r.erase(unique(r.begin(), r.end()), r.end());
		if (r.size() > 2) {
        //간선이 2개를 초과할때, 정점의 개수와 다르다면 선인장이 아닙니다.
			if (edges != r.size()) { cout << "Not cactus"; return 0; }
			for (int c : r) {
				if (!v[c])v[c] = 1;
                //두개 이상의 bcc에 한 정점이 겹치면 선인장이 아닙니다.
				else {
					cout << "Not cactus";
					return 0;
				}
			}
		}
	}
    //선인장입니다.
	cout << "Cactus";
}

선인장 그래프

 

 

'baekjoon' 카테고리의 다른 글

[백준] 3067 Coins  (0) 2023.07.04
[백준] 6672 Electricity  (0) 2023.07.04
[백준] 11400 단절선  (0) 2023.07.03
[백준] 11266 단절점 + BCC 이중 연결 요소  (0) 2023.07.03
[백준]11689 GCD(n,k) - 오일러 파이 함수  (0) 2023.07.03