※ 글쓴이는 취미로 코딩을 익혀보는 사람이라 정확하지 않은 내용을 담고 있을 수 있다 ※

 

이번에 볼 문제는 백준 4324번 문제인 XYZZY이다.
문제는 아래 링크를 확인하자.

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

 

4324번: XYZZY

The input consists of several test cases. Each test case begins with n, the number of rooms. The rooms are numbered from 1 (the start room) to n (the finish room). Input for the n rooms follows. The input for each room consists of one or more lines contain

www.acmicpc.net

 

먼저 1번 방에서 N번 방까지 도달하기 위해 움직여야 하는 횟수가 상당히 많을 수 있음을 확인하자. 예를 들어 1번부터 50번 방까지로 이루어진 사이클 형태의 경로를 따라 한 바퀴 돌 때마다 에너지가 1씩 증가하고, 각각 에너지가 100씩 감소하는 51~99번 방을 거쳐 100번 방으로 도착해야 하는 형태의 그래프의 경우 거쳐야 하는 방의 수가 매우 많을 것이다. 이 문제는 한 실행에 여러 테스트케이스를 해결해야하므로, 위의 내용과 함께 생각해보면 도착할 때까지 직접 시뮬레이션을 돌리는 것은 적절한 풀이가 아닐 것이라고 결론내릴 수 있다.

위의 풀이가 비효율적인 이유는 위와 같이 사이클을 여러 번 돌아 N번 방에 도달하게 되는 경우 직접 사이클을 도는 시뮬레이션 과정이 오래 걸리기 때문이다. 이 사이클을 직접 따라 돌면서 N번 방까지 가는 과정을 무조건 살펴봐야 할까?

그렇지 않다. 이 문제에서는 N번 방의 도달 가능성만을 구하면 되므로, 사이클을 돌아야 하는 경우 1번 방에서 도달 가능하면서 에너지가 증가하는 사이클에 속한 각 방으로부터 N번 방으로 도달할 수 있는지를 확인하는 것으로 문제를 해결할 수 있다.

사이클을 돌아야 하는 경우와 그럴 필요가 없는 두 경우 모두에 신경써 문제를 해결하자.

아래는 제출한 소스코드이다.

#include <iostream>
#include <vector>
#include <cstring>
#include <utility>
using namespace std;

int N, K;
int E[101];
vector<int> G[101], invG[101];
int HP[101], tmp[101], mxHP[101], oldmxHP[101];
int chk[101], visited[101], ans;

void dfs(int cur) {
	visited[cur] = 1;
	if (chk[cur]) ans = 1;
	for (auto &nxt:invG[cur]) {
		if (visited[nxt]) continue;
		dfs(nxt);
	}
}

void solve() {
	for (int i = 1; i <= N; i++) G[i].clear(), invG[i].clear();
	for (int i = 1; i <= N; i++) {
		cin >> E[i] >> K;
		G[i].clear();
		while (K--) {
			int x; cin >> x;
			G[i].emplace_back(x);
			invG[x].emplace_back(i);
		}
	}
	if (N == 1) {
		cout << "winnable\n";
		return;
	}

	memset(HP, 0xff, sizeof(HP));
	memset(mxHP, 0xff, sizeof(mxHP));
	HP[1] = mxHP[1] = 100;
	for (int k = 0; k < N; k++) {
		memset(tmp, 0xff, sizeof(tmp));
		for (int cur = 1; cur <= N; cur++) {
			if (HP[cur] < 0) continue;
			for (auto &nxt:G[cur]) {
				if (HP[cur] + E[nxt] < 1) continue;
				tmp[nxt] = max(tmp[nxt], HP[cur] + E[nxt]);
			}
		}
		swap(HP, tmp);
		if (HP[N] > 0) {
			cout << "winnable\n";
			return;
		}
		for (int i = 1; i <= N; i++) mxHP[i] = max(mxHP[i], HP[i]);
	}
	for (int i = 1; i <= N; i++) oldmxHP[i] = mxHP[i];
	for (int k = 0; k < N; k++) {
		memset(tmp, 0xff, sizeof(tmp));
		for (int cur = 1; cur <= N; cur++) {
			if (HP[cur] < 0) continue;
			for (auto &nxt:G[cur]) {
				if (HP[cur] + E[nxt] < 1) continue;
				tmp[nxt] = max(tmp[nxt], HP[cur] + E[nxt]);
			}
		}
		swap(HP, tmp);
		if (HP[N] > 0) {
			cout << "winnable\n";
			return;
		}
		for (int i = 1; i <= N; i++) mxHP[i] = max(mxHP[i], HP[i]);
	}
	memset(chk, 0, sizeof(chk));
	for (int i = 1; i <= N; i++) {
		if (mxHP[i] > oldmxHP[i]) chk[i] = 1;
	}
	memset(visited, 0, sizeof(visited)), ans = 0;
	dfs(N);
	if (ans) cout << "winnable\n";
	else cout << "hopeless\n";
}

int T;

int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);

	cin >> N;
	while (N > 0) {
		solve();
		cin >> N;
	}
}
728x90

'BOJ' 카테고리의 다른 글

[BOJ 4626 // C++] 가글  (0) 2024.04.25
[BOJ 14515 // C++] Yin and Yang Stones  (0) 2024.04.24
[BOJ 23604 // C++] Chinese Remainder Theorem  (0) 2024.04.22
[BOJ 16481 // C++] 원 전문가 진우  (0) 2024.04.21
[BOJ 16509 // C++] 장군  (1) 2024.04.20

+ Recent posts