본문 바로가기

백준/C++

[Baekjoon/C++] 20529번 - 가장 가까운 세 사람의 심리적 거리

[백준] Baekjoon Online Judge

문제로 이동

 

문제

여러분은 요즘 유행하는 심리검사인 MBTI에 대해 들어보았는가?

MBTI(Myers-Briggs Type Indicator)는 C.G.Jung의 심리유형론을 근거로 하여 Katharine Cook Briggs와 Isabel Briggs Myers가 보다 쉽고 일상생활에 유용하게 활용할 수 있도록 고안한 자기보고식 성격유형지표이다. (출처: 위키백과)

MBTI는 아래와 같이 네 가지 척도로 사람들의 성격을 구분한다.

  • 외향(E) / 내향(I)
  • 감각(S) / 직관(N)
  • 사고(T) / 감정(F)
  • 판단(J) / 인식(P)

각 척도마다 두 가지 분류가 존재하므로, MBTI는 총 24=16가지 유형이 있음을 알 수 있다. 일반적으로 MBTI의 유형들은 각 분류를 나타내는 알파벳 한 글자씩을 따 네 글자로 표시하게 된다. 모든 유형의 목록은 다음과 같다.

  • ISTJ, ISFJ, INFJ, INTJ, ISTP, ISFP, INFP, INTP, ESTP, ESFP, ENFP, ENTP, ESTJ, ESFJ, ENFJ, ENTJ

MBTI 성격 유형을 이용하면 두 사람 사이의 심리적인 거리를 정의할 수 있다. 이는 두 사람의 MBTI 유형에서 서로 다른 분류에 속하는 척도의 수로 정의된다. 예를 들어, MBTI 유형이 ISTJ인 사람과 ISFJ인 사람 사이의 거리는 1이며, INTP인 사람과 ENTJ인 사람 사이의 거리는 2이다.

 

이 정의를 확장해서 세 사람 사이의 심리적인 거리도 정의할 수 있다. 세 사람 가 있을 때 이들의 심리적인 거리는

(  사이의 심리적인 거리) + (  사이의 심리적인 거리) + (  사이의 심리적인 거리)

로 정의한다.

 

대학교에서 심리학 교수로 일하는 종서는 자신이 가르치는 학생들의 심리적인 특성을 분석하고 싶어한다.

오늘이 생일인 종서를 위해 명의 학생들의 MBTI 유형이 주어질 때, 가장 가까운 세 학생 사이의 심리적인 거리를 구해보자.

 

입력

첫 줄에는 테스트 케이스의 수를 나타내는 정수 가 주어진다.

각 테스트 케이스의 첫 줄에는 학생의 수를 나타내는 하나의 정수 이 주어지며, 두 번째 줄에는 각 학생의 MBTI 성격 유형을 나타내는 문자열들이 사이에 공백을 두고 주어진다.

 

출력

각 테스트 케이스에 대한 답을 정수 형태로 한 줄에 하나씩 출력한다.

 

제한

  •  1 ≤ T ≤ 50
  •  3 ≤ N ≤ 100,000
  • 각 테스트 케이스의 의 합은 1을 넘지 않는다.

 


풀이

#include <iostream>
#include <map>
using namespace std;

map <string, int> m;

int difCnt(string a, string b, string c);
int choose();

int difCnt(string a, string b, string c) {
	int sum = 0;

	for (int i = 0; i < 4; i++)
		sum += (a[i] != b[i]) + (b[i] != c[i]) + (a[i] != c[i]);

	return sum;
}

int choose() {
	int result = 100000;
	for (auto i = m.begin(); i != m.end(); i++) {
		if (i->second > 3) return 0;

		i->second--;

		for (auto j = i; j != m.end(); j++) {
			if (j->second > 3) return 0;
			if (j->second == 0) continue;

			j->second--;

			for (auto k = j; k != m.end(); k++) {
				if (k->second > 3) return 0;
				if (k->second == 0) continue;

				result = min(result, difCnt(i->first, j->first, k->first));
			}

			j->second++;
		}

		i->second++;
	}

	return result;
}

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

	int T;
	cin >> T;

	while (T--) {
		int N;
		cin >> N;

		for (int i = 0; i < N; i++) {
			string s;
			cin >> s;

			if (m.count(s)) m[s]++;
			else m.insert({ s, 1 });
		}

		cout << choose() << '\n';

		m.clear();
	}

	return 0;
}

 

	while (T--) {
		int N;
		cin >> N;

		for (int i = 0; i < N; i++) {
			string s;
			cin >> s;

			if (m.count(s)) m[s]++;
			else m.insert({ s, 1 });
		}

		cout << choose() << '\n';

		m.clear();
	}

입력을 받고, 결과를 출력하는 부분이다. string을 입력 받았을 때, 그 값이 이전에 입력한 적 있는 값이라면 m[s]의 값을 1증가하도록 한다.

 

int choose() {
	int result = 100000;
	for (auto i = m.begin(); i != m.end(); i++) {
		if (i->second > 3) return 0;

		i->second--;

		for (auto j = i; j != m.end(); j++) {
			if (j->second > 3) return 0;
			if (j->second == 0) continue;

			j->second--;

			for (auto k = j; k != m.end(); k++) {
				if (k->second > 3) return 0;
				if (k->second == 0) continue;

				result = min(result, difCnt(i->first, j->first, k->first));
			}

			j->second++;
		}

		i->second++;
	}

	return result;
}

입력 받은 MBTI 중 3개를 선택하는 함수이다. 이번에 선택한 MBTI 유형을 가진 학생이 3명 이상이라면 이들의 최소 심리적 거리는 0이므로 바로 0을 return한다.

만약 위와 같은 경우가 없다면 선택한 3개의 MBTI의 심적인 거리를 difCnt()함수로 계산하여, result와 그 값을 비교한다.

MBTI 3개를 선택할 때 같은 MBTI를 입력 받은 것보다 더 많이 선택하는 것을 방지하기 위해 second 값에 변화를 주도록 했다.

 

int difCnt(string a, string b, string c) {
	int sum = 0;

	for (int i = 0; i < 4; i++)
		sum += (a[i] != b[i]) + (b[i] != c[i]) + (a[i] != c[i]);

	return sum;
}

선택한 3개의 MBTI의 심적 거리를 계산한 뒤 return하는 함수이다.