본문 바로가기

Algorithm

백준 2099번 The game of death

반응형

문제

The game of death는 확률성과 함께 전략이 요구되는 게임인데, N명의 사람들이 원을 이루고 모여 앉은 후 시작된다. 사람들에게는 1번부터 N번까지 번호가 매겨져 있다고 하자.

각 사람은 자신의 양 손을 이용해서 동시에 두 명의 사람을 가리킨다. 자기 자신은 가리킬 수 없으나 자신이 가리키는 두 사람이 꼭 다를 필요는 없다. 그리고 첫 사람이 자연수 K를 하나 정한 뒤에, 자신의 가리키고 있는 두 사람 중 한 사람을 지목한다. 첫 번째로 지목된 사람은 마찬가지로 자신이 가리키고 있는 두 사람 중 한 사람을 지목한다. 마찬가지로 지목된 사람이 같은 방법으로 사람들 지목해 나가며, K번째로 지목된 사람이 걸리게 되는 게임이다.

예를 들어 N=4이고 K=2인 경우를 생각해 보자. 1번 사람은 2번과 4번 사람을 지목했고, 2번 사람은 1번과 3번을, 3번 사람은 1번과 4번을, 그리고 4번 사람은 2번과 2번을 지목했다고 하자. 4번 사람이 시작했을 때 1번이 걸릴 수 있으나, (4->2->1) 1번 사람이 시작했을 때는 4번 사람이 걸릴 수 없다.

N과 K, 그리고 각 사람이 지목한 두 사람에 대한 정보가 주어졌을 때, a번 사람이 시작했을 때 b번 사람이 걸리는 경우가 있는지 없는지를 알아내는 프로그램을 작성하시오. a와 b의 쌍은 M개 주어진다.

입력

첫째 줄에 세 정수 N(2<=N<=200)과 K(1<=K<=1,000,000)와 M(1<=M<=1,000,000)이 주어진다. 다음 N개의 줄에 걸쳐 각 사람이 지목한 두 명의 사람이 번호로 주어진다. 다음 M개의 줄에 걸쳐 각 줄에 a와 b가 주어진다.

출력

M개의 줄에, 입력받은 순서대로 a번 사람으로 시작해서 b번 사람이 걸리는 경우가 있으면 'death'를, 걸리게 할 수 없으면 'life'를 출력한다.

 

간선의 정보를 담은 인접 행렬이 있을 때,

인접 행렬의 K 곱에서 i,j 가 값이 존재한다면 i에서 K번째에 j에 도달함을 의미.

 

따라서 행렬 K 제곱 할 수 있으면 되는데 시간 초과가 발생하므로 분할 정복으로 해결해야 함.

 

그리고 배열 반환이 애매하므로 vector 반환으로 할 수 있는데

vector<vector<bool> > 을 타입으로 지정하고 이걸 반환하면 됨.

이중 벡터 초기화는 vec c(n,vector<bool>(n)) 이렇게 가능.

 

#include <iostream>
#include <string.h>
#include <deque>
#include<queue>
#include<vector>
#include<map>
#include <algorithm>

using namespace std;
int N, K, M;
typedef vector<vector<bool>> vec;


vec operator * (const vec& a, const vec& b) {
	int n = a.size();
	vec c(n, vector<bool>(n));
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			for (int k = 0; k < n; k++) {
				if (a[i][k] * b[k][j]) c[i][j] = 1;
			}
		}
	}
	return c;
}

vec go(vec x, int k)
{
	int n = x.size();
	vec ans(n, vector<bool>(n));

	if (k == 1)
	{
		return x;
	}
	else if (k == 0)
	{
		for (int i = 0; i < n; i++)
		{
			for (int j = 0; j < n; j++)
			{
				ans[i][j] = 1;
			}
		}
		return ans;
	}


	if (!(k % 2))
	{
		ans = go(x, k / 2);
		ans = ans * ans;
	}
	else
	{
		ans = x * go(x, k - 1);
	}
	return ans;
}


int main(void)
{
	cin >> N >> K >> M;
	vec x(N, vector<bool>(N));
	for (int i = 0; i < N; i++)
	{
		int a, b;
		scanf(" %d %d", &a, &b);
		a--;
		b--;
		x[i][a] = 1;
		x[i][b] = 1;
	}

	vec ans = go(x, K);
	for (int i = 0; i < M; i++)
	{
		int a, b;
		scanf(" %d %d", &a, &b);
		a--;
		b--;
		if (ans[a][b])
		{
			puts("death");
		}
		else
		{
			puts("life");
		}
	}
	return 0;
}

반응형