문제
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;
}
'Algorithm' 카테고리의 다른 글
1213. [S/W 문제해결 기본] 3일차 - String (0) | 2020.09.19 |
---|---|
백준 10830 행렬 제곱 oo (0) | 2020.09.19 |
백준 1890번 점프 (0) | 2020.09.18 |
백준 1937번 욕심쟁이 판다 (0) | 2020.09.17 |
백준 14002번 가장 긴 증가하는 부분 수열 4 (0) | 2020.09.17 |