https://school.programmers.co.kr/learn/courses/30/lessons/64064
프로그래머스
SW개발자를 위한 평가, 교육, 채용까지 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프
programmers.co.kr
#include <string>
#include <vector>
#include <set>
#include<iostream>
#include<algorithm>
using namespace std;
// ✅ 1️ `banned_id` 패턴과 `user_id`가 매칭되는지 확인하는 함수
bool isMatch(string user, string banned)
{
if (user.size() != banned.size()) return false; // 길이가 다르면 불가능
for (int i = 0; i < user.size(); i++)
{
if (banned[i] != '*' && user[i] != banned[i])
{
return false; // '*'가 아닌 문자가 다르면 매칭 실패
}
}
return true; // 패턴과 일치함
}
// ✅ 2️ 각 `banned_id`에 매칭될 수 있는 `user_id` 리스트 구성
vector<vector<string>> getMatchingList(vector<string>& user_id, vector<string>& banned_id)
{
vector<vector<string>> matching(banned_id.size());
for (int i = 0; i < banned_id.size(); i++)
{
for (string user : user_id)
{
if (isMatch(user, banned_id[i]))
{
matching[i].push_back(user); // 매칭되는 유저 저장
}
}
}
return matching;
}
// ✅ 3️ 백트래킹을 사용하여 가능한 모든 제재 조합을 찾음
void findCombinations(vector<vector<string>>& matching, vector<string>& chosen, set<set<string>>& results, int depth)
{
if (depth == matching.size())
{
set<string> temp(chosen.begin(), chosen.end());
results.insert(temp); // 중복된 조합을 방지
return;
}
for (string user : matching[depth])
{
if (find(chosen.begin(), chosen.end(), user) == chosen.end())
{ // 중복 방지
chosen.push_back(user);
findCombinations(matching, chosen, results, depth + 1);
chosen.pop_back(); // 백트래킹
}
}
}
// ✅ 4️ `solution()` 함수: 전체 로직을 수행하는 메인 함수
int solution(vector<string> user_id, vector<string> banned_id)
{
vector<vector<string>> matching = getMatchingList(user_id, banned_id);
set<set<string>> results; // 중복 없는 조합 저장
vector<string> chosen;
findCombinations(matching, chosen, results, 0);
return results.size(); // 가능한 제재 아이디 조합의 개수
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
//vector<string> user_id;
string id;
int n;
int m;
cin >> n>>m;
vector<string> user_id(n);
vector<string> banned_id(m);
for (int i = 0; i < n; i++)
{
cin>>user_id[i];
}
//for (auto a : user_id) cout << a << " ";
for (int i = 0; i < m; i++)
{
cin >> banned_id[i];
}
//for (auto a : banned_id) cout << a << " ";
cout << solution(user_id, banned_id) << '\n';
return 0;
}
불량 사용자 목록(banned_id)과 user_id 리스트를 비교하여,
가능한 모든 조합을 찾고 중복을 방지하면서 경우의 수를 구하는 문제를 해결
주요 알고리즘은 백트래킹(Backtracking)과 set을 활용한 중복 제거
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
int n, m;
cin >> n >> m; // 사용자 수와 불량 사용자 수 입력받기
vector<string> user_id(n);
vector<string> banned_id(m);
for (int i = 0; i < n; i++) {
cin >> user_id[i]; // 사용자 ID 입력
}
for (int i = 0; i < m; i++) {
cin >> banned_id[i]; // 불량 사용자 패턴 입력
}
// 결과 출력
cout << solution(user_id, banned_id) << '\n';
return 0;
}
🔹 입력 예시
5 2
frodo fradi crodo abc123 frodoc
fr*d* abc1**
🔹 입력된 벡터 상태
user_id = { "frodo", "fradi", "crodo", "abc123", "frodoc" }
banned_id = { "fr*d*", "abc1**" }
bool isMatch(string user, string banned) {
if (user.size() != banned.size()) return false; // 길이가 다르면 불가능
for (int i = 0; i < user.size(); i++) {
if (banned[i] != '*' && user[i] != banned[i]) {
return false; // '*'가 아닌 문자가 다르면 매칭 실패
}
}
return true; // 패턴과 일치함
}
🔹 예제 실행
isMatch("frodo", "fr*d*"); // true (frodo → fr*d*)
isMatch("crodo", "fr*d*"); // true (crodo → fr*d*)
isMatch("abc123", "abc1**"); // true (abc123 → abc1**)
isMatch("frodoc", "fr*d*"); // false (frodoc ≠ fr*d*)
vector<vector<string>> getMatchingList(vector<string>& user_id, vector<string>& banned_id)
{
vector<vector<string>> matching(banned_id.size());
for (int i = 0; i < banned_id.size(); i++) {
for (string user : user_id) {
if (isMatch(user, banned_id[i])) {
matching[i].push_back(user); // 매칭되는 유저 저장
}
}
}
return matching;
}
🔹 예제 실행 결과
banned_id = { "fr*d*", "abc1**" }
user_id = { "frodo", "fradi", "crodo", "abc123", "frodoc" }
matching = {
{ "frodo", "crodo" }, // "fr*d*"에 매칭되는 user_id들
{ "abc123" } // "abc1**"에 매칭되는 user_id들
}
void findCombinations(vector<vector<string>>& matching, vector<string>& chosen, set<set<string>>& results, int depth) {
if (depth == matching.size()) {
set<string> temp(chosen.begin(), chosen.end());
results.insert(temp); // 중복된 조합을 방지
return;
}
for (string user : matching[depth]) {
if (find(chosen.begin(), chosen.end(), user) == chosen.end()) { // 중복 방지
chosen.push_back(user);
findCombinations(matching, chosen, results, depth + 1);
chosen.pop_back(); // 백트래킹
}
}
}
🔹 백트래킹 탐색 과정
1. "fr*d*"에 가능한 ID → { "frodo", "crodo" }
2. "abc1**"에 가능한 ID → { "abc123" }
가능한 조합:
{ "frodo", "abc123" }
{ "crodo", "abc123" }
int solution(vector<string> user_id, vector<string> banned_id)
{
vector<vector<string>> matching = getMatchingList(user_id, banned_id);
set<set<string>> results; // 중복 없는 조합 저장
vector<string> chosen;
findCombinations(matching, chosen, results, 0);
return results.size(); // 가능한 제재 아이디 조합의 개수
}
🔹 최종 출력
2
✅ 불량 사용자 패턴과 user_id 매칭 함수 구현
✅ 가능한 매칭 리스트 구성 (vector<vector<string>>)
✅ 백트래킹을 활용하여 모든 조합 탐색
✅ set을 활용해 중복된 조합 방지
✅ 최적의 O(8!) 풀이로 해결 가능!
백준 31464 초콜릿 괴도 코코 (Sweet) (0) | 2025.04.06 |
---|---|
Programmers 양과 늑대 (0) | 2025.01.22 |
백준 17825 주사위 윷놀이 (0) | 2025.01.21 |
백준 17270// 연예인은 힘들어//다익스트라 알고리즘 (Dijkstra's Algorithm)// (0) | 2025.01.20 |
항해//프로그래머스 60060// 가사 검색/c++// (3) | 2025.01.15 |