문제

N과M(3) 백준 15651번


리뷰

오름차순 수열을 출력하되, *숫자 중복을 허용한다. *

코드

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

/*  n과m (3)
중복 허용
1부터 n까지 자연수 중에서 m개를 고른 수열  
*/ 

int n, m;
int arr[10]; // 출력할 수열을 담는다.  

void go(int index){  // index 0부터 m-1 까지 어떤 수로 채울지 선택하는 함수  

    if(index == m){ // index m-1까지 모든 수를 골랐으니까 수열 출력 

        for(int i = 0; i < m; i++){ // 수열 출력
            printf("%d ", arr[i]);
        }
        cout << '\n';        
        return; 
    } 

    for(int i = 1; i <= n; i++){ // 1부터 n까지 수를 '중복 허용'하여 선택
        arr[index] = i;
        go(index+1); // 다음 자리 숫자를 고르러 재귀호출 
    }

}

int main(void){

       scanf("%d %d", &n, &m);

      go(0); // 0번째 자리에 어떤 수를 넣을지 선택한다.  

    return 0;
} 

문제

N과M(4) 백준 15652번


리뷰

비내림차순 수열을 출력하되, *숫자 중복을 허용한다. *

비내림차순은 '같은 숫자가 연속되거나 오름차순'이다. 예를 들어, 11223 같은 수열이 비내림차순이다.

중복 허용이니까 중복체크할 배열이 필요 없다.


코드 1

#include <iostream>
using namespace std;


/*   n과m (4)
중복 허용, 비내림차순  
1부터 n까지 자연수 중에서 m개를 고른 수열  
*/ 

int n, m;
int arr[10]; // 출력할 수열을 담는다.  

void go(int index, int start_num){  

    if(index == m){ // 수열 출력
        for(int i = 0; i < m; i++){
            printf("%d ", arr[i]);
        }
        cout << '\n';
        return; 
    } 

    for(int i = start_num; i <= n; i++){ // 선택 범위의 시작 숫자만 정해준다. 
        arr[index] = i; 
        go(index+1, i); // 반드시 i 보다 큰 수부터 다시 선택해야 하는게 아니다.(비내림차순)
    }

}

int main(void){

       scanf("%d %d", &n, &m);

      go(0, 1); // 0번째 자리에 어떤 수를 넣을지 선택한다.  start는 선택범위의 시작숫자. 

    return 0;
} 

코드 2

m 개로 이루어진 배열 arr를 채우는 '완전탐색' DFS로 풀이했다.

#include <iostream>
using namespace std;

/*  n과m (4)  DFS로 푼 코드 
중복 허용, 비내림차순  
1부터 n까지 자연수 중에서 m개를 고른 수열  
*/ 

int n, m;
int arr[10]; // 숫자 m개를 골라 저장할 수열  

void dfs(int start_num, int cnt){ // 비내림차순 이니까 start_num 활용.  cnt는 선택한 숫자 개수

    if(cnt == m){ // 0 ~ m-1 까지 총 m 개 선택 완료해서 수열을 출력.
        for(int i = 0; i < m; i++)
            cout << arr[i] << ' ';
        cout << '\n';
        return;
    }

    for(int i = start_num; i <= n; i++){ // 비내림차순
        arr[cnt] = i;  // cnt자리에 i숫자를 넣는다. 선택한 것.
        dfs(i, cnt+1); 
        // 비내림차순이니까 i 부터 다시 선택할 수 있게 한다. 윗줄에서 선택했으니 cnt+1을 넘긴다. 
    }
} 


int main(void){

      scanf("%d %d", &n, &m);

      dfs(1, 0);  // 1부터 시작한다. 고른 개수.

    return 0;
} 
728x90

'알고리즘 > 백준' 카테고리의 다른 글

부분수열의 합 백준 1182번  (0) 2020.10.20
외판원순회2 백준 10971번 c++  (0) 2020.10.20
N과 M(1), (2)  (0) 2020.10.20
설탕배달 백준 2839번  (0) 2020.10.07
분해합 백준 2231번 c++  (0) 2020.10.07

N과 M문제집

1부터 12까지 시리즈가 있는 N과 M 문제집

순열, 조합을 연습하는 N과 M 시리즈 문제다. 백준님께서 1~4번 문제가 매우 중요하다고 하셨다.

문제

N과M(1) 백준 15649번

리뷰

재귀 호출을 이용해서 N개중에 M개를 고른다.

M개를 고를 때, permu() 함수는 매개변수로 지금 '몇 번째' 숫자를 고른다는 기준을 잡는다.

int check[ ] 배열을 이용해 특정 숫자를 골랐는지/안골랐는지 표시한다.

숫자 중복을 허용하지 않기 때문에 선택 여부 표시를 위해 필요하다.

코드

#include <iostream>
using namespace std;

int N, M;
int check[10]; // 확인 여부  
int answer[10]; // 선택한 인덱스  

void permu(int idx){ // 'idx' 번째에 어떤 수를 놓을지 고른다. 

    if(idx > M){ // 이미 M개를 골랐으니까, M번째를 초과하는 순간 종료. 

        // 수열 출력 
        for(int p = 1; p <= M; p++){
            cout << answer[p] << ' ';
        }
        cout << '\n';

        return; 
    }

    for(int i = 1; i <= N; i++){ 

        if(check[i]) continue; // 이미 선택된 수는 지나간다 

        check[i] = 1; // 선택 함
        answer[idx] = i; // idx 자리에 숫자 i 배치 

        permu(idx+1); // 다음 자리의 숫자 고르러 재귀          

        check[i] = 0; // 선택 안함  
    }
}

int main(void){

    freopen("input.txt", "rt", stdin);

    cin >> N >> M;

    permu(1);

    return 0;    
}

문제

N과M(2) 백준 15650번

백준님이 강조하셨다 중요하다고.

리뷰

오름차순 수열을 출력하되, 숫자가 중복되지 않도록 한다.

즉, 이미 고른 숫자보다 큰 숫자부터 골라야 한다.

코드 1

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

// N과 M (2)  

int N, M;
bool check[10];
int answer[10];

void go(int index, int start){

    if(index == M){
        // 수열 출력 
        for(int i = 0; i < M; i++){
            cout << answer[i] << ' ';
        } 
        cout << '\n';
        return;
    }

    for(int i = start; i <= N; i++){
        if(check[i]) continue; // 이미 선택된 숫자라면 지나간다. 

        check[i] = true;
        answer[index] = i; // index 자리에 i를 선택한다. 
        go(index+1, i+1); // index+1 자리에 (==다음 자리)숫자를 고르기 위해 재귀 호출.
        check[i] = false; 
    }

}

int main(void){

     scanf("%d %d", &N, &M);

    go(0, 1); // 0번째를 채우자.  

    return 0;
} 

코드2

선택 한다/ 안한다의 관점

함수 시그니처는 아래와 같다.

void go(int num, int selected_cnt);

// num 에는 1부터 n까지의 숫자가 들어온다.  1, 2, 3, ... n 
// selected_cnt는 0부터 m-1까지 숫자가 들어온다. 

1부터 n까지 수가 들어오는데, 이 숫자를 선택 할지, 말지를 선택한다.

selected_cnt 가 m이 되는 순간 수열을 출력한다.

선택 한다면, selected_cnt 자리에 num을 넣는다.

arr[selected_cnt] = num; // 선택함  
go(num+1, selected_cnt+1);

arr[selected_cnt] = 0; // 선택 안함  
go(num+1, selected_cnt);
#include <iostream>
using namespace std;

// n과 m (2)

int n, m;
int arr[10]; // num 숫자를 선택 한다/안한다를 표시  

// num 에는 1부터 n까지의 숫자가 들어온다. 
// selected_cnt는 0부터 m-1까지 숫자가 들어온다. 

void go(int num, int selected_cnt){ // num 숫자를 선택 한다/안한다 ,  선택한 수의 개수 

    if(selected_cnt == m){
        // 수열 출력
        for(int i = 0; i < m; i++){
            printf("%d ", arr[i]);
        }
        cout << '\n';

        return; 
    } 

    if(num > n) return; // n을 초과하면 리턴  

    arr[selected_cnt] = num; // 선택함  
    go(num+1, selected_cnt+1);

    arr[selected_cnt] = 0; // 선택 안함  
    go(num+1, selected_cnt);

}

int main(void){

       scanf("%d %d", &n, &m);

      go(1, 0); 

    return 0;
} 
728x90

'알고리즘 > 백준' 카테고리의 다른 글

외판원순회2 백준 10971번 c++  (0) 2020.10.20
N과 M (3),(4)  (0) 2020.10.20
설탕배달 백준 2839번  (0) 2020.10.07
분해합 백준 2231번 c++  (0) 2020.10.07
소트인사이드 백준 1427번  (0) 2020.10.02

문제

설탕 배달 백준 2839번


리뷰

3kg 또는 5kg 봉지를 최소 개수로 활용해서 N kg을 맞추면 된다.

봉지의 개수가 최대일 때는 3kg 만 이용하는거니까 N / 3 개가 최대 개수가 된다.

즉, N =18kg 일 때, 18 / 3 = 6봉지가 최대 개수다.

그래서 3kg 을 0개 이용할 때 부터 6개 이용하는 경우까지 확인하도록 반복문을 만들었다.

int maxN = N/3;  

for(int i = 0; i <= maxN; i++ ){

    int cnt = i; // 봉지 개수 
    int sum = N-(i*3); // 3kg 곱해서 N에서 뺀 kg 

    if(  sum % 5 == 0){
        cnt += (sum/5);
        min_cnt = min(cnt, min_cnt);
    }
}

3kg 봉지를 몇개 이용하고, 나머지 kg은 sum이 된다.

만약, 5kg 봉지로 sum이 나누어 떨어진다면, 정확하게 N kg을 맞출 수 있는 경우다!

여기서 min_cnt를 갱신할 수 있다.


마지막에서 최소 봉지 개수 min_cnt 가 여전히 2e9로 초기값과 같다면, -1을 출력한다.

    if(min_cnt == 2e9) cout << -1;
    else cout << min_cnt;

맞은 코드

#include <iostream>
#include <cmath>
#include <algorithm> 
using namespace std;

int N;
int min_cnt = 2e9; // 최소 봉지 개수 

int main(void){

    scanf("%d", &N); // 목표 kg 

    int maxN = N/3;  

    for(int i = 0; i <= maxN; i++ ){

        int cnt = i; // 봉지 개수 
        int sum = N-(i*3); // 3kg 곱해서 N에서 뺀 kg 

        if( sum % 5 == 0){
            cnt += (sum/5);
            min_cnt = min(cnt, min_cnt);
        }
    }

    if(min_cnt == 2e9) cout << -1;
    else cout << min_cnt;

    return 0;
} 
728x90

'알고리즘 > 백준' 카테고리의 다른 글

N과 M (3),(4)  (0) 2020.10.20
N과 M(1), (2)  (0) 2020.10.20
분해합 백준 2231번 c++  (0) 2020.10.07
소트인사이드 백준 1427번  (0) 2020.10.02
수 정렬하기3 백준 10989번  (0) 2020.10.02

문제

분해합 백준 2231번

리뷰

N의 생성자를 찾으려면 1부터 N-1 까지 전부 탐색하면 된다.

N은 1이상 100만 이하의 수가 들어오니까 for문으로 찾아도 2초 시간제한을 초과하지 않는다.

각 자리의 수가 가질 수 있는 최대 숫자는 9이다.

 

N이 219 일 때, 219는 3 자리수이다.

219에서 9를 3번 빼면 219의 생성자의 최소값을 구할 수 있다. 219 - 9 -9 -9 = 192

따라서 192 부터 218까지 탐색해서 생성자를 구해도 된다. 1부터 탐색할 필요가 없다.

맞은 코드 1

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

int N, answer;

int Sum_total(int n){ 

    int sum = n; // 일단 자기 자신을 더한다. 
    while(n > 0){ 
        sum += (n%10);  // 각 자리수를 더한다 
        n /= 10;
    }
    return sum;
}

int main(void){

    cin >> N;

    for(int i = 1; i < N; i++){

        int sum = Sum_total(i);

        if(sum == N) {
            answer = i;  // 생성자 찾음 
            break;
        }
    }    

    printf("%d", answer);  

    return 0;
} 

맞은 코드 2

#include <iostream>
#include <cmath>
#include <algorithm> 
#include <functional>
using namespace std;

int N, answer; // 생성자 못찾으면 answer = 0

int main(void){

    cin >> N;

    int tempN = N;
    int len = 0;

    while(tempN > 0){ // 1. N의 자리수 len에 구하기  
        tempN /= 10;
        len++;
    }

    int start_n = len*9; // 자리수 만큼 9를 뺸다 

    for(int i = start_n; i < N; i++){

        int sum = i;
        int temp = i;

        while(temp > 0){ // 2. 각 수의 자리수의 합  
            sum += (temp%10);
            temp /= 10;
        }

        if(sum == N) {
            answer = i; // 생성자 찾음 
            break;
        }
    }    

    printf("%d", answer);

    return 0;
} 
728x90

'알고리즘 > 백준' 카테고리의 다른 글

N과 M(1), (2)  (0) 2020.10.20
설탕배달 백준 2839번  (0) 2020.10.07
소트인사이드 백준 1427번  (0) 2020.10.02
수 정렬하기3 백준 10989번  (0) 2020.10.02
팰린드롬수 백준 1259번  (0) 2020.10.02

문제

소트인사이드 백준 1427번


리뷰

입력받은 수 N을 한 자리 숫자 씩 잘라서 벡터에 넣는다.

greater() 로 내림차순 정렬한다.

#include <algorithm> 
#include <functional>

sort(v.begin(), v.end(), greater<int>()); // 내림차순 정렬 

맞은 코드

#include <iostream>
#include <vector>
#include <algorithm> 
#include <functional>
using namespace std;

int N, len;
vector<int> v;   

int main(void){

    scanf("%d", &N);

    while(N > 0){
        v.push_back(N % 10); // 한 개씩 벡터에 넣는다     
        N /= 10;
        len++;
    }

     sort(v.begin(), v.end(), greater<int>()); // 내림차순 정렬 

     for(int i = 0; i < len; i++){   
        printf("%d",v[i]);
    }

    return 0;
} 


728x90

'알고리즘 > 백준' 카테고리의 다른 글

설탕배달 백준 2839번  (0) 2020.10.07
분해합 백준 2231번 c++  (0) 2020.10.07
수 정렬하기3 백준 10989번  (0) 2020.10.02
팰린드롬수 백준 1259번  (0) 2020.10.02
체스판 다시 칠하기 백준 1018번  (0) 2020.10.02

문제

수 정렬하기3 백준 10989번


리뷰

계수정렬(Counting sort) 를 써야 풀리는 문제다.

각 숫자의 개수를 배열 c에 저장한다. 입력받는 숫자는 10,000보다 작거나 같은 자연수이다.

배열 c는 10001 로 크기를 잡는다.

int N, num;
int c[10001];  // 개수를 저장할 배열 

    for(int i = 1; i <= N; i++){ // 1. 각 숫자의 개수를 센다  
        scanf("%d", &num);
        c[num]++;
    }

개수를 센 만큼 숫자 i를 출력 한다.

0개면 출력할 필요 없으니까, 1개 이상인 경우만 출력한다.

for(int i = 1; i < 10001; i++){     // 2. 개수만큼 i를 출력 

    if(c[i]){ // 개수 1이상이면 출력 

        for(int j = 0; j < c[i]; j++){
            printf("%d ", i);
        }
    }
}  

맞은 코드

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

int N, num;
int c[10001];  // 개수를 센다  

int main(void){

    scanf("%d", &N);

    for(int i = 1; i <= N; i++){ // 1. 각 숫자의 개수를 센다  
        scanf("%d", &num);
        c[num]++;
    }

    for(int i = 1; i < 10001; i++){     // 2. 개수만큼 i를 출력 

        if(c[i]){ // 개수 1이상이면 출력 

            for(int j = 0; j < c[i]; j++){
                printf("%d ", i);
            }
        }
    } 

    return 0;
} 

728x90

'알고리즘 > 백준' 카테고리의 다른 글

분해합 백준 2231번 c++  (0) 2020.10.07
소트인사이드 백준 1427번  (0) 2020.10.02
팰린드롬수 백준 1259번  (0) 2020.10.02
체스판 다시 칠하기 백준 1018번  (0) 2020.10.02
골드바흐 파티션 백준 17103번  (0) 2020.10.02

문제

팰린드롬수 백준 1259번


리뷰

수의 숫자들을 뒤에서부터 읽어도 같다면 그 수는 팰린드롬수다.

121, 12421 등은 팰린드롬수다. 123, 1231은 뒤에서부터 읽으면 다르므로 팰린드롬수가 아니다.


% 연산으로 숫자를 벡터에 숫자 한 개씩 넣는다.

가운데 인덱스를 기준으로 양끝 숫자를 비교한다.


맞은 코드

#include <iostream>
#include <string>
#include <vector>
using namespace std;

int n;

int main(void){

    while(1){
        vector<int> v;
        string st = "yes";
        int len = 0;

        cin >> n;
        if(n==0) break; // 프로그램 종료 

        while(n > 0){
            v.push_back(n % 10); // 한 개씩 벡터에 넣는다     
            n /= 10;
            len++;
        }

        len--;

        for(int i = 0; i <= len/2; i++){ // 가운데 인덱스를 기준으로 양끝 숫자를 비교
            if(v[i] != v[len-i]) st = "no";
        }
        cout << st << '\n';

    }

    return 0;
} 

728x90

+ Recent posts