백준 1062 가르침
가르침 (백준 1062)
https://www.acmicpc.net/problem/1062
bitset을 이용하여 각 문자의 알파벳을 나누어 저장하는 것까지는 완료하였으나
이후 풀이 과정 중 DFS를 전혀 떠올리지 못하였다
결국 블로그를 참조하였고
백트래킹과 재귀에 대한 연습이 재차 필요하단 것을 다시 느끼게 되었다
참고 : https://nanyoungkim.tistory.com/173
Code
#include <iostream>
#include <vector>
#include <string>
using namespace std;
//N 최대 50개
// word로 미리 '필요한 알파벳'들을 저장해둔다
int word[50];
int N, K;
int maxi = 0;
//선택을 할수 있는 개수, 시작점 , 체크 여부
void DFS(int toPick, int start, int checked)
{
// 재귀 종료
if (toPick == 0)
{
// 그 알파벳들로 N개 단어 중 몇개 읽을 수 있는지 카운트해서 최대값 찾기
// checked로 저장을 해둔 알파벳으로
// word 배열을 돌면서 해당 checked와 비트 체크를 해준다
// and 연산으로 자기 자신이 나왔다는 것은
// 그 단어가 필요로 하는 알파벳을 모두 골랐다는 뜻
int cnt = 0;
for (int i = 0; i < N; i++)
{
if ((word[i] & checked) == word[i])
{
cnt++;
}
}
if (maxi < cnt)
{
maxi = cnt;
}
return;
}
for (int i = start; i < 26; i++)
{
//방문 안 한 경우에만
if ((checked & (1 << i)) == 0)
{
// int 변수로 체크해주기
checked |= (1 << i);
DFS(toPick - 1, i, checked); // 재귀
checked &= ~(1 << i); // 이후 풀어준다
}
}
}
int main()
{
int checked = 0;
cin >> N >> K;
string str;
for (int i = 0; i < N; i++)
{
cin >> str;
int num = 0;
for (int j = 0; j < str.length(); j++)
{
num |= 1 << (str[j] - 'a');
}
word[i] = num;
}
//anta ~ tica 읽으려면 최소 a,n,t,i,c 5개 이상은 알고 있어야함
if (K < 5)
{
cout << 0;
}
else if (K == 26)
{
cout << N;
}
else
{
//a, n, t, i, c 를 이미 알고 있음을 초기화.
checked |= 1 << ('a' - 'a');
checked |= 1 << ('n' - 'a');
checked |= 1 << ('t' - 'a');
checked |= 1 << ('i' - 'a');
checked |= 1 << ('c' - 'a');
DFS(K - 5, 0, checked);
cout << maxi;
}
return 0;
}
해결 아이디어
- 알파벳 단어의 ‘개수’가 중요한 문제이다
기본적으로 a c i n t 가 모든 단어에 포함되어야 하기에
주어지는 k의 개수가 4개 미만이면 0을,
반대로 k가 26개라면 모든 알파벳을 담을수 있으므로 n개를 출력 - int로 비트마스킹을 할 변수를 선언 후,
dfs(백트래킹)를 통해 ‘선택하지 않은’ 알파벳을 골라
k-5개 까지 진행한다
(위의 다섯 알파벳이 포함되어야 하기에, 선택할 수 있는 단어의 개수인 k에서
5를 빼준다) - 모든 단어를 고른 경우(pickCount == 0)
해당 알파벳이 들어간 int 형 변수와
기존에 비트마스킹을 통해 만들어질 단어의 int 와 &연산자로 비교
해당 연산을 통해 다시 단어가 나오는 경우,
check 변수는 word[i]의 모든 알파벳 단어를 가지고 있는 상황이기에
cnt++ 해준다 - 가능한 모든 수를 돌면서 가장 높은 maxI를 출력한다
댓글남기기