코딩테스트 연습 - 후보키 | 프로그래머스 (programmers.co.kr)
학번, 이름
을 고르는 것과 이름, 학번
을 고르는 것은 동일하므로 순열 문제가 아니라 조합 문제입니다.1, 3
이라는 후보키가 있다면, 1, 2, 3
번 열 조합이 유일성을 만족하더라도 최소성을 위반하므로 후보키가 될 수 없습니다.for (int i = 1; i <= col; ++i) {
// col개의 공간을 true로 초기화하고 앞에서부터 i개를 false로 초기화.
vector<bool> comb(col, true);
for (int j = 0; j < i; ++j) comb[j] = false;
// 조합을 구한다.
do {
/* ... */
} while(next_permutation(begin(comb), end(comb)));
}
0
인 배열을 만듭니다. (01111
, 00111
같이)bool checkUniqueness(const vector<vector<string>>& relation, const vector<int>& cols, int row) {
for (int i = 0; i < row; ++i)
for (int j = i + 1; j < row; ++j) {
int cnt = 0;
for (const int& col : cols)
if (relation[i][col] == relation[j][col]) cnt++;
if (cnt == cols.size()) return false;
}
return true;
}
i
와 j
, 이중 반복문을 이용해서 모든 tuple에 대해 유일성을 검사합니다.bool checkMinimality(const vector<int>& cols, const vector<vector<int>>& cands) {
for (const vector<int>& cand : cands) {
int cnt = 0;
for (const int& c : cand)
if (find(begin(cols), end(cols), c) != end(cols)) cnt++;
if (cnt == cand.size()) return false;
}
return true;
}
선택해야하는 열의 개수가 증가하므로 바깥 for문을 사용함 = n
내부에서 조합을 구함 =
∴
#include <vector>
#include <algorithm>
using namespace std;
// 최소성 검사, 후보키 조합이 포함된 조합은 최소성을 만족하지 않는다. (e.g. {1, 2}가 후보키면 {1, 2, n}은 불가)
bool checkMinimality(const vector<int>& cols, const vector<vector<int>>& cands) {
for (const vector<int>& cand : cands) {
int cnt = 0;
for (const int& c : cand)
if (find(begin(cols), end(cols), c) != end(cols)) cnt++;
if (cnt == cand.size()) return false;
}
return true;
}
// 유일성 검사. 선택된 모든 열에 대해 튜플값이 동일하면 유일성을 만족하지 않는다.
bool checkUniqueness(const vector<vector<string>>& relation, const vector<int>& cols, int row) {
for (int i = 0; i < row; ++i)
for (int j = i + 1; j < row; ++j) {
int cnt = 0;
for (const int& col : cols)
if (relation[i][col] == relation[j][col]) cnt++;
if (cnt == cols.size()) return false;
}
return true;
}
int solution(vector<vector<string>> relation) {
int row = relation.size(), col = relation[0].size();
vector<vector<int>> candidateKey;
for (int i = 1; i <= col; ++i) { // 선택할 attributes(열)의 개수
// 조합을 구할 때 사용할 배열 초기화
vector<int> comb(col, 1);
for (int j = 0; j < i; ++j) comb[j] = 0;
do {
// 선택된 열의 조합을 추출한다.
vector<int> selectedCols;
for (int j = 0; j < col; ++j) if (comb[j] == 0) selectedCols.push_back(j);
// 유일성과 최소성을 검사한 뒤 통과한 조합은 후보키로 저장한다.
if (checkUniqueness(relation, selectedCols, row) == false) continue;
if (checkMinimality(selectedCols, candidateKey) == false) continue;
candidateKey.push_back(selectedCols);
} while(next_permutation(begin(comb), end(comb)));
}
return candidateKey.size();
}