728x90
728x90

문제 링크 : www.acmicpc.net/problem/4375

 

4375번: 1

2와 5로 나누어 떨어지지 않는 정수 n(1 ≤ n ≤ 10000)가 주어졌을 때, 1로만 이루어진 n의 배수를 찾는 프로그램을 작성하시오.

www.acmicpc.net

 

 

문제

2와 5로 나누어 떨어지지 않는 정수 n(1 ≤ n ≤ 10000)가 주어졌을 때, 1로만 이루어진 n의 배수를 찾는 프로그램을 작성하시오.

입력

입력은 여러 개의 테스트 케이스로 이루어져 있다. 각 테스트 케이스는 한 줄로 이루어져 있고, n이 주어진다.

출력

1로 이루어진 n의 배수 중 가장 작은 수의 자리수를 출력한다.

 

 


접근 방법

숫자를 1, 11, 111, 1111,,,,로 키워가면서 N으로 나눠지는지 따지는 문제이다.

그러나 계속 숫자를 한 자리씩 키워나간다면 long long int 의 범위(-9,223,372,036,854,775,808~9,223,372,036,854,775,807)도 넘어가게 되고 시간초과가 뜬다. 그래서 modular 연산의 활용이 필요하다.

 

x mod N = (x mod N) mod N 임을 이용해보자.

 

예를 들어, 111이 N으로 나눠지지 않아서 1111로 넘어갈 때, 1111을 바로 다음 반복문으로 넘기는 것이 아니라 mod N 연산을 해주고 넘기는 것이다. 그러면 숫자가 계속 커지는 것을 방지할 수 있다.

 

숫자가 매우 커질 때 modular 연산을 이용해서 줄일 수 있다는 것을 기억하자!

//
//  수학_BOJ4375_1.cpp
//  Coding_Test_Practice
//
//  Created by 김난영 on 2021/04/28.
//  Copyright © 2021 KimNanyoung. All rights reserved.
//

#include <iostream>
#include <cmath>

using namespace std;

int main(){
    
    int N;
    int k = 0;
    while(cin >> N){
        int ans = 1;
        k = 1;
        
        while(1){
            if(ans % N == 0){
                break;
            }
            else{
                k++;
                ans = ans*10 + 1;
                ans %= N;				//mod 연산을 해 준 결과를 다음 반복문으로 넘긴다.
            }
        }
        
        cout << k << "\n";
    }

    return 0;
}

 

 

참고)

 while(cin >> input) 은 입력이 종료될 때 까지 받는다. 

같은 의미로는 아래와 같다.

while(1){

  if(cin.eof() == true) {break;}

}

 

 

 

728x90
728x90

문제 링크 : www.acmicpc.net/problem/1789

 

1789번: 수들의 합

첫째 줄에 자연수 S(1 ≤ S ≤ 4,294,967,295)가 주어진다.

www.acmicpc.net

 

 

 

문제

서로 다른 N개의 자연수의 합이 S라고 한다. S를 알 때, 자연수 N의 최댓값은 얼마일까?

입력

첫째 줄에 자연수 S(1 ≤ S ≤ 4,294,967,295)가 주어진다.

출력

첫째 줄에 자연수 N의 최댓값을 출력한다.

 

 

접근 방법

 

서로 다른 자연수를 더해서 S를 만드는데, 이때 어떻게 해야 그 서로 다른 자연수들의 개수가 최대가 될까 생각해보았다.

결론은 1부터 차례로 2, 3, 4, ,,,,씩 더해야 '서로 다른' 과 '최대 개수' 조건을 만족한다. 자연수들의 차를 1씩으로 최대한 작은 수들로 더해야 S를 최대한 여러개의 자연수 합으로 나타낼 수 있기 때문이다. 

 

즉 1부터 x까지 자연수를 더한수가 S보다 크거나 같아질 때 x-1이 답이 된다. 

//
//  BS_BOj1789_수들의 합.cpp
//  Coding_Test_Practice
//
//  Created by 김난영 on 2021/04/26.
//  Copyright © 2021 KimNanyoung. All rights reserved.
//

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


int main(){
    
    long S; cin >> S;
    
    long ans = 0;
    long x = sqrt(2*S);
    for(long i = x; i>=1; i--){
        if(i*i + i <=2*S){
            ans = i;
            break;
        }
    }
    cout << ans;
    
    return 0;
}

 

 

 

이 문제를 이진 탐색으로 풀어보자.

start = 1, end = S로 잡고 start 부터 end의 중간값을 mid로 잡는다. 

1부터 mid까지의 합(mid*(mid+1) / 2)을 구한다.

    1) 그 값이 S보다 크면 mid 값이 더 작아져야 하므로 end 를 줄인다. (end = mid-1로 지정한 뒤 다시 탐색)

    2) 그 값이 S보다 작거나 같으면 mid 값이 더 커져야 하므로 start를 키운다. (start = mid+1로 지정한 뒤 다시 탐색)

 

참고로 이진탐색은

원소가 정렬되어 있어야 하며, 각 원소에 랜덤 액세스가 가능할 때 적용할 수 있다. 우리는 정렬된 자연수를 고려하므로 이진탐색을 적용할 수 있다.

 

//
//  BS_BOj1789_수들의 합.cpp
//  Coding_Test_Practice
//
//  Created by 김난영 on 2021/04/26.
//  Copyright © 2021 KimNanyoung. All rights reserved.
//

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


int main(){
    
    long S; cin >> S;
    
    long ans = 0;
    long start = 1; long end = S;
    
    while(start<=end){
        long mid = (start+end)/2;
        
        if(mid*(mid+1)/2 <= S){
            ans = mid;
            start = mid+1;
        }
        else{
            end = mid-1;
        }
    }
    
    cout << ans;
    
    return 0;
}

728x90
728x90

문제 링크 : www.acmicpc.net/problem/2579

 

2579번: 계단 오르기

계단 오르기 게임은 계단 아래 시작점부터 계단 꼭대기에 위치한 도착점까지 가는 게임이다. <그림 1>과 같이 각각의 계단에는 일정한 점수가 쓰여 있는데 계단을 밟으면 그 계단에 쓰여 있는 점

www.acmicpc.net

 

 

문제

계단 오르기 게임은 계단 아래 시작점부터 계단 꼭대기에 위치한 도착점까지 가는 게임이다. <그림 1>과 같이 각각의 계단에는 일정한 점수가 쓰여 있는데 계단을 밟으면 그 계단에 쓰여 있는 점수를 얻게 된다.

예를 들어 <그림 2>와 같이 시작점에서부터 첫 번째, 두 번째, 네 번째, 여섯 번째 계단을 밟아 도착점에 도달하면 총 점수는 10 + 20 + 25 + 20 = 75점이 된다.

계단 오르는 데는 다음과 같은 규칙이 있다.

  1. 계단은 한 번에 한 계단씩 또는 두 계단씩 오를 수 있다. 즉, 한 계단을 밟으면서 이어서 다음 계단이나, 다음 다음 계단으로 오를 수 있다.
  2. 연속된 세 개의 계단을 모두 밟아서는 안 된다. 단, 시작점은 계단에 포함되지 않는다.
  3. 마지막 도착 계단은 반드시 밟아야 한다.

따라서 첫 번째 계단을 밟고 이어 두 번째 계단이나, 세 번째 계단으로 오를 수 있다. 하지만, 첫 번째 계단을 밟고 이어 네 번째 계단으로 올라가거나, 첫 번째, 두 번째, 세 번째 계단을 연속해서 모두 밟을 수는 없다.

각 계단에 쓰여 있는 점수가 주어질 때 이 게임에서 얻을 수 있는 총 점수의 최댓값을 구하는 프로그램을 작성하시오.

입력

입력의 첫째 줄에 계단의 개수가 주어진다.

둘째 줄부터 한 줄에 하나씩 제일 아래에 놓인 계단부터 순서대로 각 계단에 쓰여 있는 점수가 주어진다. 계단의 개수는 300이하의 자연수이고, 계단에 쓰여 있는 점수는 10,000이하의 자연수이다.

출력

첫째 줄에 계단 오르기 게임에서 얻을 수 있는 총 점수의 최댓값을 출력한다.

 

 

 


 

 

접근 방법

 

 

1) 현재 계단을 밟지 않고 건너 뛰는 경우

2) 현재 계단을 밟는 경우

 

이렇게 두가지로 나눌 수 있다.

1)번의 경우에 계단의 합의 최대값은 직전의 최대값과 같다. 이 경우엔 현재 계단을 선택하지 않으므로 3개 연속 유무를 신경쓰지 않아도 된다.

2)번의 경우에 계단의 합의 최대값은, 현재 계단을 포함해서 3개 이상 연속되는 경우를 제외해야 한다. 그러므로 직전 계단에서 2개 이상 연속한 경우를 제외하고, 나머지 후보들을 비교해서 최대합을 찾으면 된다.

 

문제의 입력 예시를 보자.

6개의 계단 값은 10 20 15 25 10 20 이다.

벡터 배열안에 <합, 연속해서 밟은 계단 수> 를 저장했고, 저장할 때마다 합을 비교해서 마지막에 최대합을 dp[]에 저장했다.

벡터 배열 값을 보면 아래와 같다. 

10    vecArr[0] : <0,0>/  <10,1>  -> dp[0] = 10

20   vecArr[1] : <10,0> / <0+20, 1> <10+20, 2>  ->dp[1] = 30

15    vecArr[2] : <30,0> / <10+15, 1> <0+20+15,2>  ->dp[2] =  35

25   vecArr[3] : <35, 0> / <30+25, 1> <10+15+25, 2>  -> dp[3] = 55

10   vecArr[4] : <55,0> / <35+10, 1> <30+25+10, 2>  -> dp[4] = 65

20   vecArr[5] : <65,0> / <55+20, 1> <35+10+20, 2>  -> dp[5] = 75

 

//
//  DP_BOJ2579_계단오르기.cpp
//  Coding_Test_Practice
//
//  Created by 김난영 on 2021/04/11.
//  Copyright © 2021 KimNanyoung. All rights reserved.
//

#include <iostream>
#include <algorithm>
#include <vector>
#include <utility>

using namespace std;

int stair[300] = {0};
int dp[300] = {0};
vector<pair<int,int>> vecArr[300];

int main(){
    
    int N; cin >> N;
    for(int i = 0; i<N; i++){
        cin >> stair[i];
    }
    
    //dp[0], dp[1] 초기화
    vecArr[0].push_back(make_pair(0,0));            //-1
    vecArr[0].push_back(make_pair(stair[0],1));     //0
    
    dp[0] = stair[0];
    
    vecArr[1].push_back(make_pair(dp[0], 0));               //0 x
    vecArr[1].push_back(make_pair(stair[1], 1));            //x 1
    vecArr[1].push_back(make_pair(stair[0] + stair[1], 2)); //0 1
    
    int maxi=0;
    for(int i = 0; i<3; i++){
        if(maxi<vecArr[1][i].first) maxi = vecArr[1][i].first;
    } dp[1] = maxi;
    
    
    
    for(int i = 2; i<=N-1; i++){
        
        //case 1 : 현재 계단 안 밟는 경우
        if(i!=N-1){     //문제의 조건에서 마지막 계단은 무조건 밟는다고 했음
            vecArr[i].push_back(make_pair(dp[i-1], 0));     //직전 계단까지 왔을 때 최대값
        }
        
        //case 2 : 현재 계단 밟는 경우
        int maxi = 0;
        for(int j = 0; j<vecArr[i-1].size(); j++){
            int conti = vecArr[i-1][j].second;
            if(conti==2) continue;                  //직전 계단까지 2개 연속해서 밟은 경우, 3개 연속 못 밟음
            
            int sum = stair[i] + vecArr[i-1][j].first;
            if(maxi < sum) maxi = sum;
            vecArr[i].push_back(make_pair(sum,conti+1));    //현재 계단 밟았으므로 연속해서 밟은 계단 수 1증가해서 저장
 
        }
        dp[i] = maxi;
        
    }
    cout << dp[N-1];
    
    return 0;
}

 

728x90
728x90

문제 링크 : www.acmicpc.net/problem/1110

 

1110번: 더하기 사이클

0보다 크거나 같고, 99보다 작거나 같은 정수가 주어질 때 다음과 같은 연산을 할 수 있다. 먼저 주어진 수가 10보다 작다면 앞에 0을 붙여 두 자리 수로 만들고, 각 자리의 숫자를 더한다. 그 다음,

www.acmicpc.net

 

 

문제

0보다 크거나 같고, 99보다 작거나 같은 정수가 주어질 때 다음과 같은 연산을 할 수 있다. 먼저 주어진 수가 10보다 작다면 앞에 0을 붙여 두 자리 수로 만들고, 각 자리의 숫자를 더한다. 그 다음, 주어진 수의 가장 오른쪽 자리 수와 앞에서 구한 합의 가장 오른쪽 자리 수를 이어 붙이면 새로운 수를 만들 수 있다. 다음 예를 보자.

26부터 시작한다. 2+6 = 8이다. 새로운 수는 68이다. 6+8 = 14이다. 새로운 수는 84이다. 8+4 = 12이다. 새로운 수는 42이다. 4+2 = 6이다. 새로운 수는 26이다.

위의 예는 4번만에 원래 수로 돌아올 수 있다. 따라서 26의 사이클의 길이는 4이다.

N이 주어졌을 때, N의 사이클의 길이를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 N이 주어진다. N은 0보다 크거나 같고, 99보다 작거나 같은 정수이다.

출력

첫째 줄에 N의 사이클 길이를 출력한다.

 

 

 


 

접근 방법

알고리즘 분류는 문자열이지만 그냥 정수형으로 입력 받아서 나눗셈 연산을 이용해서 해결했다.

//
//  문자열_BF1110_더하기사이클.cpp
//  Coding_Test_Practice
//
//  Created by 김난영 on 2021/04/11.
//  Copyright © 2021 KimNanyoung. All rights reserved.
//

#include <iostream>
#include <string>

using namespace std;


int main(){
    
    int num, num1, num2, ans=0;
    cin >> num;
    
    if(num<10) {
        num1 = 0;
        num2 = num;
    }
    else{
        num1 = num/10;
        num2 = num-num1*10;
    }
    
    while(1){
        ans+=1;
       
        int sum = num1 + num2;
        if(sum>9){
            int q = sum/10;
            sum = sum-q*10;
        }
        
        int newNum = num2*10 + sum;
        if(newNum==num) {
            break;
        }
        else{
            num1 = newNum/10;
            num2 = newNum - num1*10;
        }
    }
        
    cout << ans;
        
    return 0;
}

 

728x90
728x90

문제 링크 : www.acmicpc.net/problem/15686

 

15686번: 치킨 배달

크기가 N×N인 도시가 있다. 도시는 1×1크기의 칸으로 나누어져 있다. 도시의 각 칸은 빈 칸, 치킨집, 집 중 하나이다. 도시의 칸은 (r, c)와 같은 형태로 나타내고, r행 c열 또는 위에서부터 r번째 칸

www.acmicpc.net

 

 

문제

크기가 N×N인 도시가 있다. 도시는 1×1크기의 칸으로 나누어져 있다. 도시의 각 칸은 빈 칸, 치킨집, 집 중 하나이다. 도시의 칸은 (r, c)와 같은 형태로 나타내고, r행 c열 또는 위에서부터 r번째 칸, 왼쪽에서부터 c번째 칸을 의미한다. r과 c는 1부터 시작한다.

이 도시에 사는 사람들은 치킨을 매우 좋아한다. 따라서, 사람들은 "치킨 거리"라는 말을 주로 사용한다. 치킨 거리는 집과 가장 가까운 치킨집 사이의 거리이다. 즉, 치킨 거리는 집을 기준으로 정해지며, 각각의 집은 치킨 거리를 가지고 있다. 도시의 치킨 거리는 모든 집의 치킨 거리의 합이다.

임의의 두 칸 (r1, c1)과 (r2, c2) 사이의 거리는 |r1-r2| + |c1-c2|로 구한다.

예를 들어, 아래와 같은 지도를 갖는 도시를 살펴보자.

 

0은 빈 칸, 1은 집, 2는 치킨집이다.

(2, 1)에 있는 집과 (1, 2)에 있는 치킨집과의 거리는 |2-1| + |1-2| = 2, (5, 5)에 있는 치킨집과의 거리는 |2-5| + |1-5| = 7이다. 따라서, (2, 1)에 있는 집의 치킨 거리는 2이다.

(5, 4)에 있는 집과 (1, 2)에 있는 치킨집과의 거리는 |5-1| + |4-2| = 6, (5, 5)에 있는 치킨집과의 거리는 |5-5| + |4-5| = 1이다. 따라서, (5, 4)에 있는 집의 치킨 거리는 1이다.

이 도시에 있는 치킨집은 모두 같은 프랜차이즈이다. 프렌차이즈 본사에서는 수익을 증가시키기 위해 일부 치킨집을 폐업시키려고 한다. 오랜 연구 끝에 이 도시에서 가장 수익을 많이 낼 수 있는  치킨집의 개수는 최대 M개라는 사실을 알아내었다.

도시에 있는 치킨집 중에서 최대 M개를 고르고, 나머지 치킨집은 모두 폐업시켜야 한다. 어떻게 고르면, 도시의 치킨 거리가 가장 작게 될지 구하는 프로그램을 작성하시오.

입력

첫째 줄에 N(2 ≤ N ≤ 50)과 M(1 ≤ M ≤ 13)이 주어진다.

둘째 줄부터 N개의 줄에는 도시의 정보가 주어진다.

도시의 정보는 0, 1, 2로 이루어져 있고, 0은 빈 칸, 1은 집, 2는 치킨집을 의미한다. 집의 개수는 2N개를 넘지 않으며, 적어도 1개는 존재한다. 치킨집의 개수는 M보다 크거나 같고, 13보다 작거나 같다.

출력

첫째 줄에 폐업시키지 않을 치킨집을 최대 M개를 골랐을 때, 도시의 치킨 거리의 최솟값을 출력한다.

 

 

 


 

접근 방법

 

1) 기본 DFS + 기본 BFS -> 시간 초과

처음에는 DFS로 치킨 집 중 M개를 선택하고, 선택이 완료되면 BFS로 각 집에서 치킨집까지 최소 거리를 구했다. 그랬더니 답은 제대로 나왔지만 시간 초과가 떴다.

 

 

2) 기본 DFS + BFS 사용x -> 시간 초과

M의 최대가 13밖에 안되니 BFS 대신 직접 각 집에서 치킨집까지 거리를 abs()를 이용해서 구했다.

 

 

3) 중복조합으로 DFS 개선 + BFS 사용x -> 통과

치킨 집을 2개 선택한다 했을 때, <1번, 2번> 이나 <2번, 1번>이나 같으므로 중복 조합을 이용했다.

 

 

//
//  BF_BOJ15686_치킨배달.cpp
//  Coding_Test_Practice
//
//  Created by 김난영 on 2021/04/11.
//  Copyright © 2021 KimNanyoung. All rights reserved.
//
#include <iostream>
#include <vector>
#include <algorithm>
#include <utility>
#include <string.h>
#include <queue>
#include <cmath>
using namespace std;

int N, M;

int map[51][51];
int fromStart[51][51];
int newMap[51][51];
vector<pair<int,int>> homeVec;       //1
vector<pair<int,int>> chickenVec;   //2
int visited[100] = {0};
vector<pair<int,int>> pickedChick;   //2중 M개 선택

//위 오 아 왼
int dr[4] = {-1,0,1,0};
int dc[4] = {0,1,0,-1};
int mini = 100000000;
int answer =100000000;


void pickChickDFS(int toPick, int start){

    if(toPick==0){
        
        int sum=0;
        //각 집에서 pickChick까지의 거리들 중 최소값들의 합
        for(int i = 0; i<homeVec.size();i++){
            mini = 100000000;
            
            for(int j = 0; j<pickedChick.size(); j++){
                int dis = abs(homeVec[i].first-pickedChick[j].first)
                + abs(homeVec[i].second - pickedChick[j].second);
                
                if(mini>dis) mini = dis;
            }
            sum+=mini;
            if(sum>answer) return;
        }
        
        if(answer>sum) answer = sum;
        return;
    }
    
    for(int i = start; i<chickenVec.size(); i++){
        if(visited[i]==0){
            visited[i] = 1;
            pickedChick.push_back(chickenVec[i]);
            pickChickDFS(toPick-1, i);
            pickedChick.pop_back();
            visited[i] = 0;
        }
    }
}


int main(){
    cin >> N >> M;
    
    for(int i = 1; i<=N; i++){
        for(int j = 1; j<=N; j++){
            cin >> map[i][j];
            if(map[i][j]==1){   homeVec.push_back(make_pair(i,j)); }
            if(map[i][j]==2){   chickenVec.push_back(make_pair(i,j)); }
        }
    }
    
    pickChickDFS(M, 0);
    cout << answer;
    
    return 0;
}

728x90
728x90

문제 링크 : www.acmicpc.net/problem/2210

 

2210번: 숫자판 점프

111111, 111112, 111121, 111211, 111212, 112111, 112121, 121111, 121112, 121211, 121212, 211111, 211121, 212111, 212121 이 가능한 경우들이다.

www.acmicpc.net

 

 

 

문제

5×5 크기의 숫자판이 있다. 각각의 칸에는 숫자(digit, 0부터 9까지)가 적혀 있다. 이 숫자판의 임의의 위치에서 시작해서, 인접해 있는 네 방향으로 다섯 번 이동하면서, 각 칸에 적혀있는 숫자를 차례로 붙이면 6자리의 수가 된다. 이동을 할 때에는 한 번 거쳤던 칸을 다시 거쳐도 되며, 0으로 시작하는 000123과 같은 수로 만들 수 있다.

숫자판이 주어졌을 때, 만들 수 있는 서로 다른 여섯 자리의 수들의 개수를 구하는 프로그램을 작성하시오.

입력

다섯 개의 줄에 다섯 개의 정수로 숫자판이 주어진다.

출력

첫째 줄에 만들 수 있는 수들의 개수를 출력한다.

 

배열을 char 형으로 설정해서 string의 push_back(), 

//
//  DFS_BOJ2210_숫자판점프.cpp
//  Coding_Test_Practice
//
//  Created by 김난영 on 2021/04/11.
//  Copyright © 2021 KimNanyoung. All rights reserved.
//

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

char map[5][5];
//위 오 아 왼
int dr[4] = {-1,0,1,0};
int dc[4] = {0,1,0,-1};

vector<string> strVec;
void DFS(int r, int c, int toPick, string str){
        
    if(toPick==0){
        if(find(strVec.begin(), strVec.end(), str) == strVec.end()){
            strVec.push_back(str);
        }
        return;
    }
    
    for(int i = 0; i<4; i++){
        int nr = r + dr[i];
        int nc = c + dc[i];
        
        if(nr<0 || nr>=5 || nc<0 || nc>=5) continue;
        
        str.push_back(map[nr][nc]);
        DFS(nr, nc, toPick-1,str);
        str.pop_back();
    }
}

int main(){
    
    for(int i = 0; i<5; i++){
        for(int j = 0; j<5; j++){
            cin >> map[i][j];
        }
    }
    
    for(int i = 0; i<5; i++){
           for(int j = 0; j<5; j++){
               DFS(i,j,6, "");
           }
    }

    cout << strVec.size();
    
    return 0;
}

728x90
728x90

문제 링크 : www.acmicpc.net/problem/16943

 

16943번: 숫자 재배치

두 정수 A와 B가 있을 때, A에 포함된 숫자의 순서를 섞어서 새로운 수 C를 만들려고 한다. 즉, C는 A의 순열 중 하나가 되어야 한다.  가능한 C 중에서 B보다 작으면서, 가장 큰 값을 구해보자. C는 0

www.acmicpc.net

 

 

문제

두 정수 A와 B가 있을 때, A에 포함된 숫자의 순서를 섞어서 새로운 수 C를 만들려고 한다. 즉, C는 A의 순열 중 하나가 되어야 한다. 

가능한 C 중에서 B보다 작으면서, 가장 큰 값을 구해보자. C는 0으로 시작하면 안 된다.

입력

첫째 줄에 두 정수 A와 B가 주어진다.

출력

B보다 작거나 같은 C중에서 가장 큰 값을 출력한다. 그러한 C가 없는 경우에는 -1을 출력한다.

 

 

 


 

 

 

접근 방법

정수 A를 string으로 형변환 한 뒤, 각 문자를 vector에 넣고 DFS를 돌려서 완전 탐색을 해 주었다. 

DFS를 돌면서 vector안의 각 요소를 str에 push_back()으로 붙이고 pop_back()으로 빼주었다.

 

A의 자리수만큼 수를 만들었으면 정수형으로 다시 바꾼뒤 문제의 조건을 만족하는지 확인한다.

 

//
//  BF_BOJ16943_숫자재배치.cpp
//  Coding_Test_Practice
//
//  Created by 김난영 on 2021/04/05.
//  Copyright © 2021 KimNanyoung. All rights reserved.
//

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

int visited[10] = {0};
vector<char> vec;
int A,B;
string strB;
int maxi = 0;
int answer = 0;
void DFS(int toPick, string str){
    
    if(toPick==0){
        int num = stoi(str);

        if(num!=A && num<B){        //B보다 작으면서
            if(maxi<num) {          //그 중 가장 큰 값
                maxi = num;
                answer = num;
            }
        }
    }
    
    for(int i = 0; i<vec.size(); i++){
        
        if(visited[i]==0){
            if(str.length()==0 && vec[i]=='0') continue;        //처음 0이 오면 안됨
            visited[i] = 1;
            str.push_back(vec[i]);
            DFS(toPick-1, str);
            str.pop_back();
            visited[i] = 0;
        }
    }
}


int main(){
    
    cin >> A >> B;
    
    string strA = to_string(A);
    string strB = to_string(B);
    int nLen = (int)strA.length();
    
    for(int i = 0; i<nLen; i++){
        vec.push_back(strA[i]);
    }
    
    DFS(nLen, "");
    if(answer==0) answer=-1;
    cout << answer ;
    
    return 0;
}

 

 

728x90
728x90

문제 링크 : www.acmicpc.net/problem/16938

 

16938번: 캠프 준비

난이도가 10, 30인 문제를 고르거나, 20, 30인 문제를 고르면 된다.

www.acmicpc.net

 

 

문제

알고리즘 캠프를 열려면 많은 준비가 필요하다. 그 중 가장 중요한 것은 문제이다. 오늘은 백준이를 도와 알고리즘 캠프에 사용할 문제를 고르려고 한다.

백준이는 문제를 N개 가지고 있고, 모든 문제의 난이도를 정수로 수치화했다. i번째 문제의 난이도는 Ai이다.

캠프에 사용할 문제는 두 문제 이상이어야 한다. 문제가 너무 어려우면 학생들이 멘붕에 빠지고, 문제가 너무 쉬우면 학생들이 실망에 빠지게 된다. 따라서, 문제 난이도의 합은 L보다 크거나 같고, R보다 작거나 같아야 한다. 또, 다양한 문제를 경험해보기 위해 가장 어려운 문제와 가장 쉬운 문제의 난이도 차이는 X보다 크거나 같아야 한다.

캠프에 사용할 문제를 고르는 방법의 수를 구해보자.

입력

첫째 줄에 N, L, R, X가 주어진다.

둘째 줄에는 문제의 난이도 A1, A2, ..., AN이 주어진다.

출력

캠프에 사용할 문제를 고르는 방법의 수를 출력한다.

 

 

 


 

접근 방법

2개를 뽑는다고 했을 때, {10, 30} 과 {30,10}은 같은 경우이므로 중복 조합 개념을 적용했다.

그리고 DFS를 호출할 때마다 문제의 난이도 합, 최대 난이도, 최소 난이도를 파라미터로 전달해서 조건 만족 여부 검사를 쉽게 할 수 있도록 했다.

 

 

 

//
//  BF_BOJ16938_캠프준비.cpp
//  Coding_Test_Practice
//
//  Created by 김난영 on 2021/04/04.
//  Copyright © 2021 KimNanyoung. All rights reserved.
//

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;
int N,L,R,X;

vector<int> vec;
int answer = 0;
int visited[15] = {0};

void pickDFS(int toPick, int start,  int sum, int maxi, int mini){
        
    if(toPick==0){
        if((L<=sum && sum<=R) && (X<= maxi - mini)) {
            answer++;
        }
        return;
    }
    
    for(int i = start; i<vec.size(); i++){
        if(visited[i]==0){
            visited[i] = 1;
            pickDFS(toPick-1, i, sum+vec[i], maxi<vec[i] ? vec[i]:maxi, vec[i]<mini ? vec[i]:mini);
            visited[i] = 0;
        }
    }
}


int main(){
    
    cin >> N >> L >> R >> X;
    
    for(int i = 0; i<N; i++){
        int num;    cin>> num;
        vec.push_back(num);
    }
    
    for(int i = 2; i<=N; i++){
        pickDFS(i,0, 0, 0, 1000001);
    }
    cout << answer;

    return 0;
}

 

 

주의할 점

DFS 함수  안에 다음과 같이 인자를 설정하면 틀린 답이 출력된다. 

입력예제 2인 경우,

{10,30} 일때 maxi = 30, mini = 10으로 설정되고 그 다음 조합인

{10,25} 일 때 maxi = 25로 설정되어야 하는데, 이미 maxi = 30으로 설정되어 있어서 30이 인자로 전달되기 때문이다.

for(int i = start; i<vec.size(); i++){
        if(visited[i]==0){
            visited[i] = 1;
            if(maxi<vec[i]) maxi = vec[i];
            if(vec[i]<mini) mini = vec[i];
            pickDFS(toPick-1, i, sum+vec[i], maxi, mini);
            visited[i] = 0;
        }
}

 

 

 

728x90

+ Recent posts