Skip to content

Conversation

@mj010504
Copy link
Collaborator

@mj010504 mj010504 commented Aug 12, 2025

πŸ”— 문제 링크

λΉ„λ°€ μ½”λ“œ 해독
https://school.programmers.co.kr/learn/courses/30/lessons/388352

βœ”οΈ μ†Œμš”λœ μ‹œκ°„

1μ‹œκ°„ 30λΆ„

✨ μˆ˜λ„ μ½”λ“œ

  • 문제 μžμ²΄λŠ” μ‘°ν•© 을 ν™œμš©ν•˜μ—¬ μ—¬λŸ¬ 숫자 쑰합을 λ§Œλ“€κ³  μ£Όμ–΄μ§„ 쑰건을 λ§Œμ‘±ν•˜λŠ” 숫자 μ‘°ν•©μ˜ 개수λ₯Ό κ΅¬ν•˜λŠ” κ°„λ‹¨ν•œ λ¬Έμ œμž…λ‹ˆλ‹€.
  • μ²˜μŒμ—λŠ” 1 ~ nκΉŒμ§€μ˜ λͺ¨λ“  nC5 쑰합을 κ΅¬ν•˜κΈ° μœ„ν•΄ λΉ„νŠΈλ§ˆμŠ€ν‚Ή 기법을 ν™œμš©ν–ˆμŠ΅λ‹ˆλ‹€.
μ›λž˜ μ½”λ“œ
#include<bits/stdc++.h>

using namespace std;

int m;
bool isValid(vector<int> v, vector<vector<int>> q, vector<int> ans) {
    for(int i = 0; i < q.size(); i++) {
        auto tv = q[i];
         int sum = 0;
        for(int j = 0; j < m; j++) {
            for(int k = 0; k < m; k++) {
                if(v[k] == tv[j]) {
                    sum++;
                    break;
                }
            }
        }
            
         
        if(sum != ans[i]) return false;
    
    }

    return true;
}


int solution(int n, vector<vector<int>> q, vector<int> ans) {
    int res = 0;
    m =  q[0].size();

    for(int i = 0; i < (1 << n); i++) {
        vector<int> v;
        for(int j = 0; j < n; j++) {
            if(i & (1 << j)) v.push_back(j + 1);
        }

        if(v.size() == m && isValid(v, q, ans)) {
            res++;
        }
    }


    return res;
}
  • ν•˜μ§€λ§Œ λ‹€μŒκ³Ό 같은 ν’€μ΄λŠ” μ΅œμ•…μ˜ 경우O(2^30)의 μ‹œκ°„λ³΅μž‘λ„λ₯Ό κ°€μ§ˆ 수 있기 λ•Œλ¬Έμ— ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€ 12λ²ˆλΆ€ν„° μ‹œκ°„μ΄ˆκ³Όκ°€ λ‚¬μŠ΅λ‹ˆλ‹€.
  • λ”°λΌμ„œ μ—¬λŸ¬κ°€μ§€ μ‹œκ°„μ΄ˆκ³Όλ₯Ό μ΅œμ ν™”ν•  풀이방법을 μ°Ύμ•„λ΄€μŠ΅λ‹ˆλ‹€.
  • 첫번째둜 μ‹œλ„ν•œ 방법은 두 배열을 λΉ„κ΅ν•˜μ—¬ 같은 μ›μ†Œκ°€ λͺ‡κ°œμΈμ§€ μ°ΎλŠ” λ‘œμ§μ„ 이쀑 포인터λ₯Ό μ‚¬μš©ν–ˆμŠ΅λ‹ˆλ‹€. ν•˜μ§€λ§Œ μ΄λ ‡κ²Œ 해도 μ‹œκ°„μ΄ˆκ³Όκ°€ 났고 κ΅¬κΈ€λ§ν•΄λ΄€μŠ΅λ‹ˆλ‹€.
  • ꡬ글링을 해보고 λ‚˜μ„œ μ•Œκ²Œ 된건데 q[i]의 길이가 5둜 κ³ μ •λ˜μžˆλ‹€λŠ” 사싀을 μ•Œκ²Œ λ˜μ—ˆμŠ΅λ‹ˆλ‹€. μ œκ°€ 또 문제λ₯Ό μ œλŒ€λ‘œ 읽지 μ•Šκ³  풀이λ₯Ό μ‹œμž‘ν–ˆλ„€μš”. 길이가 5둜 κ³ μ •λ˜μ–΄μžˆκΈ° λ•Œλ¬Έμ— 5쀑 for문을 μ΄μš©ν•˜μ—¬ 1 ~ nκΉŒμ§€μ˜ nC5의 λͺ¨λ“  쑰합을 λΆˆν•„μš”ν•œ 쑰합을 κ±°λ₯΄λŠ” 과정없이 ꡬ할 수 μžˆμ—ˆκ³  μ‹œκ°„μ΄ 훨씬 적게 κ±Έλ¦¬λŠ” 것을 확인할 수 μžˆμ—ˆμŠ΅λ‹ˆλ‹€.

질문

  • μ—¬λŸ¬λΆ„λ“€μ€ 쑰합이 ν•„μš”ν•  λ•Œ μ–΄λ–»κ²Œ μ²˜λ¦¬ν•˜λŠ”μ§€ κΆκΈˆν•©λ‹ˆλ‹€. μ €λŠ” 주둜 λΉ„νŠΈλ§ˆμŠ€ν‚Ή 기법을 ν™œμš©ν•©λ‹ˆλ‹€.

πŸ“š μƒˆλ‘­κ²Œ μ•Œκ²Œλœ λ‚΄μš©

  • 문제λ₯Ό 꼼꼼히 읽어야 ν•œλ‹€λŠ” κ±Έ λ‹€μ‹œ ν•œλ²ˆ λ¦¬λ§ˆμΈλ“œν–ˆμŠ΅λ‹ˆλ‹€.
  • λ‚΄κ°€ μ§œλŠ” 둜직이 μ‹œκ°„μ΄ˆκ³Όκ°€ λ‚  것 같은지 항상 μƒκ°ν•˜κ³ , 쒋은 λ°©μ•ˆμ΄ λ– μ˜€λ₯΄μ§€ μ•ŠλŠ”λ‹€λ©΄ 문제λ₯Ό λ‹€μ‹œ ν•œλ²ˆ 꼼꼼이 μ½μ–΄λ΄μ•Όν•œλ‹€λŠ” κ±Έ μ•Œμ•˜μŠ΅λ‹ˆλ‹€!

@hyeokbini
Copy link
Collaborator

μ €λŠ” 쑰합을 λ§Œλ“€ λ•Œ κ·Έλ•Œκ·Έλ•Œ 상황에 맞게 λ‹€μ–‘ν•œ 방법을 μ‹œλ„ν•˜λ €κ³  ν•˜μ§€λ§Œ, λŒ€μ²΄μ μœΌλ‘œλŠ” μž¬κ·€ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜λŠ” 것 κ°™μŠ΅λ‹ˆλ‹€.

이번 λ¬Έμ œμ—μ„œλ„ κ²°κ΅­ λͺ¨λ“  μΌ€μ΄μŠ€λ₯Ό λ§Œλ“  ν›„ 브루트포슀둜 이 μΌ€μ΄μŠ€κ°€ κ°€λŠ₯ν•œμ§€μ— λŒ€ν•΄ μ²΄ν¬ν•˜λŠ” 과정이 ν•„μš”ν•œλ°, ν•„μ—°μ μœΌλ‘œ nC5 연산을 ν•  μˆ˜λ°–μ— μ—†μŠ΅λ‹ˆλ‹€. μž¬κ·€λ₯Ό μ“Έ λ•ŒλŠ” νŒŒλΌλ―Έν„°λ‘œ μ—¬λŸ¬ λ³€μˆ˜λ₯Ό μ€˜μ•Ό ν•˜κ±°λ‚˜, 그게 μ‹«λ‹€λ©΄ λ³€μˆ˜λ₯Ό μ „μ—­μœΌλ‘œ 빼버린 후에 μ‚¬μš©ν•˜λŠ” 과정이 ν•„μš”ν•˜κΈ΄ ν•˜μ§€λ§Œ 이 방법이 λͺΈμ— μ΅μ–΄μ„œ 자주 μ‚¬μš©ν•˜κ²Œ λ˜λŠ” 것 κ°™μŠ΅λ‹ˆλ‹€.

void comb(vector<int> combination,int start)
{
    if(combination.size() == 5)
    {
        check(combination);
        return;
    }
    for(int i = start; i <= n; i++)
    {
        combination.push_back(i);
        comb(combination,i + 1);
        combination.pop_back();
    }
}

λ¬Έμ œμ—μ„œ μ‚¬μš©ν•œ μ‘°ν•© μ½”λ“œμž…λ‹ˆλ‹€. λ‹¨μˆœν•˜κ²Œ 이번 값을 μ‚¬μš©ν–ˆλ‹€λ©΄ λ‹€μŒ κΉŠμ΄μ—μ„œλŠ” κ·Έ κ°’λΆ€ν„° λ°˜λ³΅λ¬Έμ„ μ‹œμž‘ν•˜λŠ” λ‘œμ§μž…λ‹ˆλ‹€.

μ•„λž˜λŠ” 제좜 μ½”λ“œμž…λ‹ˆλ‹€. 문제 ν‘Έμ‹œλŠλΌ κ³ μƒν•˜μ…¨μ–΄μš”!

λΉ„λ°€ μ½”λ“œ 해독/c++
#include <bits/stdc++.h>

using namespace std;
int n;
vector<vector<int>> q;
vector<int> ans;
int answer;


void check(vector<int> comb)
{
    for(int i = 0; i < q.size(); i++)
    {
        int checkcount = 0;
        vector<bool> used(n + 1,false);
        for(int j = 0; j < 5; j++)
        {
            used[q[i][j]] = true;
        }
        for(int j = 0; j < 5; j++)
        {
            if(used[comb[j]])
            {
                checkcount++;
            }
        }
        if(checkcount != ans[i])
        {
            return;
        }
    }
    answer++;
    return;
}

void comb(vector<int> combination,int start)
{
    if(combination.size() == 5)
    {
        check(combination);
        return;
    }
    for(int i = start; i <= n; i++)
    {
        combination.push_back(i);
        comb(combination,i + 1);
        combination.pop_back();
    }
}

int solution(int n_in, vector<vector<int>> q_in, vector<int> ans_in) {
    n = n_in;
    q = q_in;
    ans = ans_in;
    vector<int> combination;
    comb(combination,1);
    return answer;
}

Copy link
Collaborator

@Seol-Munhyeok Seol-Munhyeok left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

5개만 λ½‘λŠ” κ±°λ‹ˆκΉŒ 5쀑 for λ¬ΈκΉŒμ§€λŠ” μ†”μ§νžˆ ν•΄λ³Όλ§Œν•˜κΈ° λ•Œλ¬Έμ— κ°„λ‹¨ν•œ κ±°λ©΄ for문으둜 ν•˜κ±°λ‚˜, λ˜λŠ” 혁빈 λ‹˜μ²˜λŸΌ μž¬κ·€ν•¨μˆ˜λ‘œ μ§œκ±°λ‚˜, itertools의 combinations 라이브러리λ₯Ό μ‚¬μš©ν•΄μ„œ 자주 ν’‰λ‹ˆλ‹€!
(참고둜 itertoolsμ—λŠ” μˆœμ—΄, μ€‘λ³΅μˆœμ—΄, μ‘°ν•©, 쀑볡쑰합을 λͺ¨λ‘ μ§€μ›ν•©λ‹ˆλ‹€.)

일단 n이 될 수 μžˆλŠ” μ΅œλŒ€κ°’μ΄ 30이고 κ·Έ 쀑 5개λ₯Ό λ½‘λŠ” 경우의 μˆ˜λŠ” $30C5=142506$ 이고, m이 μ΅œλŒ€ 10이고, 두 λ°°μ—΄μ—μ„œ μΌμΉ˜ν•˜λŠ” μ›μ†Œ 개수λ₯Ό νƒμƒ‰ν•˜λŠ”λ° 또 5번의 연산이 ν•„μš”ν•˜κΈ° λ•Œλ¬Έμ— 총 ν•„μš”ν•œ μ—°μ‚° μˆ˜λŠ” $142,506 \times 10 \times 5 = 7,125,300$ κ°€ λ©λ‹ˆλ‹€. 일단 μ²œλ§Œμ€ λ„˜μ§€ μ•ŠκΈ° λ•Œλ¬Έμ— ν’€ 수 μžˆκ² λ‹€κ³  μƒκ°ν–ˆμŠ΅λ‹ˆλ‹€.

λΉ„λ°€μ½”λ“œκ°€ 될 수 μžˆλŠ” λͺ¨λ“  경우의 수λ₯Ό 뽑고 κ·Έ ν›„λ³΄λ§ˆλ‹€ μž…λ ₯ν•œ μ •μˆ˜μ™€ μΌμΉ˜ν•˜λŠ” κ°œμˆ˜κ°€ μ£Όμ–΄μ§„ 것과 μΌμΉ˜ν•˜λŠ” μ§€λ₯Ό ν•˜λ‚˜ν•˜λ‚˜ λΉ„κ΅ν–ˆμŠ΅λ‹ˆλ‹€.
μ—¬κΈ°μ„œ λΉ„λ°€μ½”λ“œμ™€ q[i] κ°€ μ˜€λ¦„μ°¨μˆœμœΌλ‘œ μ •λ ¬λ˜μ–΄ μžˆλ‹€λŠ” 것도 큰 힌트인데 두 배열이 이미 정렬됨이 보μž₯되면 두 λ°°μ—΄μ—μ„œ μΌμΉ˜ν•˜λŠ” μ›μ†Œμ˜ 개수λ₯Ό κ΅¬ν•˜λŠ” 것을 νˆ¬ν¬μΈν„°λ₯Ό μ΄μš©ν•΄μ„œ $O(n)$에 ꡬ할 수 μžˆμŠ΅λ‹ˆλ‹€. λ§Œμ•½ μ •λ ¬λ˜μ–΄ μžˆμ§€ μ•Šμ•˜λ‹€λ©΄ μ œκ°€ κ΅¬ν•œ μ—°μ‚° 횟수 7,125,300 보닀 더 컀질 수 μžˆμ–΄μ„œ μ‹œκ°„ μ œν•œμ— 걸릴 μˆ˜λ„ μžˆμ—ˆμ„ 것 κ°™μŠ΅λ‹ˆλ‹€!

파이썬 풀이

from itertools import combinations

def check(x, y):
    i = j = 0
    count = 0
    while i < len(x) and j < len(y):
        if x[i] == y[j]:
            count += 1
            i += 1
            j += 1
        elif x[i] < y[j]:
            i += 1
        else:
            j += 1
    
    return count
        
            
def solution(n, q, ans):
    answer = 0
    cands = combinations(list(range(1, n+1)), 5)
    for cand in cands:
        found = True
        for q1, a1 in zip(q, ans):
            if check(cand, q1) != a1:
                found = False
                break
        if found:
            answer += 1     
        
    return answer

μ½”λ“œλ₯Ό 읽닀가 zip ν•¨μˆ˜κ°€ 뭐지? ν•˜κ³  생각할 수 μžˆλŠ”λ° 맀번 q[i]와 ans[i]λ₯Ό λ”°λ‘œ λ”°λ‘œ μ μ§€μ•Šκ³  ν•œμ€„λ‘œ μ“Έ 수 μžˆκ²Œν•˜λŠ” 파이썬 ν•¨μˆ˜λΌκ³  μƒκ°ν•˜μ‹œλ©΄ λ©λ‹ˆλ‹€.

νŒŒμ΄μ¬μ΄λΌμ„œ μ‘°ν•© λ‚ λ¨Ήν•˜λ„€ν•˜κ³  생각할 μˆ˜λ„ μžˆλŠ”λ° c++에도 next_permutation μ΄λΌλŠ” 라이브러리 ν•¨μˆ˜κ°€ μžˆμŠ΅λ‹ˆλ‹€. 이건 μˆœμ—΄λ§Œ λ½‘μ•„μ£ΌκΈ°λŠ” ν•˜λŠ”λ° μ–΄λ–»κ²Œ 잘 μ‘°μž‘ν•˜λ©΄ μ‘°ν•©μœΌλ‘œλ„ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€. μ°Έκ³ ν•˜μ‹œλ©΄ 쒋을 κ±° κ°™μŠ΅λ‹ˆλ‹€!

μ΅œκ·Όμ— ν’€μ—ˆλ˜ 리λͺ¨μ»¨ λ¬Έμ œλž‘ λΉ„μŠ·ν•œ λ°©λ²•μ΄λΌμ„œ 풀이법이 μ‰½κ²Œ λ– μ˜€λ₯Έ κ±° κ°™μŠ΅λ‹ˆλ‹€. 항상 문제 ν’€ λ•ŒλŠ” 브루트포슀둜 λ¨Όμ € ν’€λ¦¬λŠ”μ§€ ν™•μΈν•˜λŠ” μŠ΅κ΄€μ΄ μ€‘μš”ν•œ κ±° κ°™μŠ΅λ‹ˆλ‹€!

μˆ˜κ³ ν•˜μ…¨μŠ΅λ‹ˆλ‹€.

μΆ”κ°€(set μžλ£Œν˜•μ„ μ΄μš©ν•œ 풀이)

λ‹€λ₯Έ μ‚¬λžŒμ΄ ν‘Ό 풀이λ₯Ό μ‚΄νŽ΄λ³΄λŠ”λ° μ—„μ²­λ‚œ 풀이가 μžˆμ–΄μ„œ κ°€μ Έμ™”μŠ΅λ‹ˆλ‹€.

import itertools 

def solution(n, q, ans):
    f = list(itertools.combinations(range(1, n + 1), 5))

    for g, cnt in zip(q, ans):
         f = [code for code in f if len(set(code) & set(g)) == cnt]

    return len(f)

μ œκ°€ μ‹ κΈ°ν•˜λ‹€ 느꼈던 건 두 λ°°μ—΄μ—μ„œ μΌμΉ˜ν•˜λŠ” μ›μ†Œμ˜ 개수λ₯Ό κ΅¬ν•˜λŠ” λ‘œμ§μ„ len(set(code) & set(g)) == cnt둜 μ²˜λ¦¬ν•œ λΆ€λΆ„μ΄μ—ˆμŠ΅λ‹ˆλ‹€. νŒŒμ΄μ¬μ—μ„œ μ œκ³΅ν•˜λŠ” μ„ΈνŠΈ(μ§‘ν•©) μžλ£Œν˜•μ„ μ΄μš©ν•΄ 두 배열을 μ§‘ν•©μœΌλ‘œ λ§Œλ“€κ³  κ΅μ§‘ν•©μ˜ 개수둜 μ²˜λ¦¬ν–ˆμŠ΅λ‹ˆλ‹€.
투 포인터 풀이가 λ– μ˜€λ₯΄κΈ° μ–΄λ €μš΄ 것은 μ•„λ‹ˆμ§€λ§Œ μ‹œκ°„μ„ μ ˆμ•½ν•˜κΈ° μœ„ν•΄μ„œλŠ” 이런 방법도 μ•Œμ•„λ‘λ©΄ λ‚˜μ˜μ§€ μ•Šμ„ κ±° κ°™μŠ΅λ‹ˆλ‹€!

Copy link
Collaborator

@flydongwoo flydongwoo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

μ €λŠ” μ™„μ „ νƒμƒ‰μœΌλ‘œ ν’€μ–΄λ³΄μ•˜μŠ΅λ‹ˆλ‹€.
λ„ˆλ¬΄ λ³΅μž‘ν•˜κ³  μ–΄λ €μš΄ λ¬Έμ œλ„€μš” γ…œγ…œ
문제 ν‘ΈλŠλΌ κ³ μƒν•˜μ…¨μŠ΅λ‹ˆλ‹€.

μ½”λ“œ/c++
#include <string>
#include <vector>
using namespace std;

int solution(int n, vector<vector<int>> q, vector<int> ans) {
    int answer = 0;
    int q_rows = (int)q.size();
    int ans_len = (int)ans.size();

    for (int a = 1; a <= n - 4; a++) {
        for (int b = a + 1; b <= n - 3; b++) {
            for (int c = b + 1; c <= n - 2; c++) {
                for (int d = c + 1; d <= n - 1; d++) {
                    for (int e = d + 1; e <= n; e++) {
                        bool inCand[31] = { false };
                        inCand[a] = true;
                        inCand[b] = true;
                        inCand[c] = true;
                        inCand[d] = true;
                        inCand[e] = true;

                        bool ok = true;
                        for (int i = 0; i < q_rows; i++) {
                            int cnt = 0;
                            bool seen[31] = { false };
                            for (int j = 0; j < (int)q[i].size(); j++) {
                                int v = q[i][j];
                                if (1 <= v && v <= n) {
                                    if (!seen[v]) {
                                        if (inCand[v]) {
                                            cnt++;
                                        }
                                        seen[v] = true;
                                    }
                                }
                            }
                            if (i < ans_len) {
                                if (cnt != ans[i]) {
                                    ok = false;
                                    break;
                                }
                            } else {
                                ok = false;
                                break;
                            }
                        }
                        if (ok) {
                            answer++;
                        }
                    }
                }
            }
        }
    }
    return answer;
}

@mj010504 mj010504 merged commit d78665d into main Aug 14, 2025
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants