/*
* Problem :: 6987 / 월드컵
*
* Kind :: Backtracking
*
* Insight
* - 6개의 팀, 총 경기횟수는 15번
* 가능한 경우의 수는 3^15 = 14348907
* + 위에서 연산 딱 10번씩만 더한다 치면... 10^8 을 넘어서 시간초과가 날 것이다
* # 다 만들어보는 것이 이 문제를 푸는 올바른 방법이 아닐 수도 있겠다 <- 실제로 해보니 안됐다
* -> 모든 결과를 다 구한 후 주어지는 결과가 모든 결과에 있는지 살펴보는 게 아니라
* 주어지는 결과가 유효한지를 알아봐야 겠다
*
* - 그럼 뭐... 백트래킹이지
* + 주어진 결과로부터 각 경기의 가능한 결과를 생각해보자
* # A팀과 B팀의 경기결과가 무승부라면
* A팀의 무승부 수와 B팀의 무승부 수가 0 보다 커야 한다
* -> A팀의 무승부 수와 B팀의 무승부 수에서 각각 1 씩 뺀 다음,
* 다음 경기인 A팀과 C팀의 경기결과를 살펴보자
* # A팀과 B팀의 경기결과가 A팀 승리라면
* A팀의 승리 수와 B팀의 패배 수가 0 보다 커야 한다
* -> A팀의 승리 수와 B팀의 패배 수에서 각각 1 씩 뺀 다음,
* 다음 경기인 A팀과 C팀의 경기결과를 살펴보자
* # A팀과 B팀의 경기결과가 B팀 승리라면
* A팀의 패배 수와 B팀의 승리 수가 0 보다 커야 한다
* -> A팀의 패배 수와 B팀의 승리 수에서 각각 1 씩 뺀 다음,
* 다음 경기인 A팀과 C팀의 경기결과를 살펴보자
*
* - 각 팀의 승리, 무승부, 패배 수가 줄어들면서
* 어느 하나라도 0 이 되면
* 그 이후 가능한 선택지가 확 줄어든다
* + 실제로 위의 검증방식이라면 가장 시간이 오래 걸리는 입력은
* 2 2 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 (2=12개, 1=6개) 일텐데
* # 이때 결과를 검증하는 함수가 몇 번 호출되는지 알아본 결과
* 총 10183 번 호출되었다
* -> 예상보다 훨씬 적네...?
*
* Point
* - 승리, 무승부, 패배 수가 100, 1000 도 들어올 수 있다 (문제에서 딱히 범위가 정해져있지 않음!)
* + 각 수가 1 이상, 6 이하인지와
* 총 경기횟수가 15번 이므로 각 팀의 (승리, 무승부, 패배) 한 횟수의 총합은 30 이 되어야 한다
* # 이를 모두 검사해주고 그 다음에 논리적으로 가능한지 살펴보자
*
* - 총 경기횟수가 15번 밖에 되지않기 때문에
* 그냥 순서대로 어느팀끼리 경기를 하는지 사전에 정해주면 편하다
* + 그렇지 않으면... 무슨 팀이 무슨 팀이랑 경기하는지 계산해야하는데
* 이를 코드로 구현하기가 의외로 간단하지 않다
*
* - enum 을 적극적으로 활용해서 실수를 줄이자
* + 필자의 경우 (각 팀, 경기시 팀구분, 경기결과) 모두 enum 으로 정의해서
* 백트래킹 함수내 경기결과를 다루는 코드를 훨씬 수월하게 작성했다
*/
//
// BOJ
// ver.C++
//
// Created by GGlifer
//
// Open Source
#include <iostream>
#include <vector>
using namespace std;
#define endl '\n'
// Set up : Global Variables
enum Team { A, B, C, D, E, F };
enum Side { L, R };
enum Status { WIN, DRAW, LOSE };
int P[15][2] = {
{A, B}, {A, C}, {A, D}, {A, E}, {A, F},
{B, C}, {B, D}, {B, E}, {B, F},
{C, D}, {C, E}, {C, F},
{D, E}, {D, F},
{E, F}
};
// int call = 0; /* isLogicallyValid 함수가 호출된 횟수 */
// Set up : Functions Declaration
bool isVarsValid(vector<vector<int>> &score);
bool isLogicallyValid(int cnt, vector<vector<int>> &score);
int main()
{
// Set up : I/O
ios::sync_with_stdio(false);
cin.tie(nullptr);
// Set up : Input
for (int i=0; i<4; i++) {
/* score[team][WIN] - team 이 승리한 횟수
* score[team][DRAW] - team 이 무승부한 횟수
* score[team][LOSE] - team 이 패배한 횟수 */
vector<vector<int>> score(6, vector<int>(3, 0));
for (int j=0; j<6; j++) {
for (int k=0; k<3; k++) {
cin >> score[j][k];
}
}
// Process
/* 먼저 각 팀의 (승리, 무승부, 패배) 한 횟수가 값적으로 유효한지 살펴보고
* 그 다음 이 결과가 논리적으로 가능한 결과인지 알아봄 */
bool valid = isVarsValid(score) && isLogicallyValid(0, score);
// Control : Output
cout << ((valid) ? 1 : 0) << ' ';
// cout << call << endl;
}
}
// Helper Functions
bool isVarsValid(vector<vector<int>> &score)
/* 각 팀의 (승리, 무승부, 패배) 한 횟수가 값적으로 유효하면 true 를 반환
* 그 외 false 를 반환 */
{
int sum = 0; /* 각 팀의 (승리, 무승부, 패배) 한 횟수의 총합 */
for (int i=0; i<6; i++) {
for (int j=0; j<3; j++) {
if (score[i][j] < 0 || score[i][j] > 6) return false;
sum += score[i][j];
}
}
return sum == 30;
}
bool isLogicallyValid(int cnt, vector<vector<int>> &score)
/* 각 팀의 (승리, 무승부, 패배) 한 횟수가 논리적으로 유효하면 true 를 반환
* 그 외 false 를 반환 */
{
// call++; /* 함수 호출 횟수 증가 */
/* 15번의 경기를 모두 치르면 바로 이 경우가 초기 score 로부터 가능한 결과 */
if (cnt == 15) return true;
int tl = P[cnt][L]; /* 왼쪽 팀 */
int tr = P[cnt][R]; /* 오른쪽 팀 */
/* 시나리오 1. 왼쪽 팀 승리 */
/* 왼쪽 팀의 승리한 횟수와 오른쪽 팀의 패배한 횟수가 0 보다 크면 */
if (score[tl][WIN] > 0 && score[tr][LOSE] > 0) {
score[tl][WIN]--; score[tr][LOSE]--; /* 각각에서 1 씩 빼고 */
if (isLogicallyValid(cnt+1, score)) /* 다음 경기로 넘어감 */
return true; /* 이 시나리오가 가능할 경우
* 바로 true 를 반환하며 함수 종료 */
score[tl][WIN]++; score[tr][LOSE]++; /* Reset */
}
/* 시나리오 2. 무승부 */
/* 왼쪽 팀의 무승부한 횟수와 오른쪽 팀의 무승부한 횟수가 0 보다 크면 */
if (score[tl][DRAW] > 0 && score[tr][DRAW] > 0) {
score[tl][DRAW]--; score[tr][DRAW]--; /* 각각에서 1 씩 빼고 */
if (isLogicallyValid(cnt+1, score)) /* 다음 경기로 넘어감 */
return true; /* 이 시나리오가 가능할 경우
* 바로 true 를 반환하며 함수 종료 */
score[tl][DRAW]++; score[tr][DRAW]++; /* Reset */
}
/* 시나리오 3. 오른쪽 팀 승리 */
/* 왼쪽 팀의 패배한 횟수와 오른쪽 팀의 이긴 횟수가 0보다 크면 */
if (score[tl][LOSE] > 0 && score[tr][WIN] > 0) {
score[tl][LOSE]--; score[tr][WIN]--; /* 각각에서 1씩 빼고 */
if (isLogicallyValid(cnt+1, score)) /* 다음 경기로 넘어감 */
return true; /* 이 시나리오가 가능할 경우
* 바로 true 를 반환하며 함수 종료 */
score[tl][LOSE]++; score[tr][WIN]++; /* Reset */
}
/* 모든 시나리오가 불가능 하다면 지금까지의 경기결과는 불가능한 결과 */
return false;
}