https://www.acmicpc.net/problem/14888

 

14888번: 연산자 끼워넣기

첫째 줄에 수의 개수 N(2 ≤ N ≤ 11)가 주어진다. 둘째 줄에는 A1, A2, ..., AN이 주어진다. (1 ≤ Ai ≤ 100) 셋째 줄에는 합이 N-1인 4개의 정수가 주어지는데, 차례대로 덧셈(+)의 개수, 뺄셈(-)의 개수, 곱셈(×)의 개수, 나눗셈(÷)의 개수이다. 

www.acmicpc.net

주어진 N개의 숫자의 위치는 변하지 않고 숫자 사이의 연산자의 위치만 바꿔서 계산 결과의 최솟값과 최댓값을 출력하는 문제이다.

solve함수에서 index번째에서 사용할 수 있는 연산자를 사용하는 모든 경우를 구해준다.

연산자를 선택할 때마다 해당 연산자를 사용해서 계산한 값을 넘겨준다.

사용한 연산자는 처음 입력받은 사용할 수 있는 개수에서 -1을 해주고 탐색에서 돌아온 경우 다시 +1을 해준다.

이 부분을 안 해줘서 계속 최솟값과 최댓값이 같은 값으로 나왔었다...

 

N-1 개의 모든 연산자를 결정해준 경우 최종 계산된 값을 ans 벡터에 추가해준다.

마지막으로 ans 벡터를 정렬해주면 맨 앞에 위치한 값이 최솟값이고 맨 마지막에 위치한 값이 최댓값이 된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int n;
vector<int> num;
vector<int> ans;
 
 
void solve(int index, int op[], int result) {
    //모든 연산자를 선택해준 경우
    if(index == n-1) {
        //계산 결과를 ans 벡터에 넣어준다.
        ans.push_back(result);
        return;
    }
    
    for(int i=0; i<4; i++) {
        //사용할 수 있는 i번째 연산자가 없는 경우
        if(op[i] == 0continue;
        
        //연산자를 사용한다.
        op[i] -= 1;
 
        //각각 덧셈인 경우, 뺄셈인 경우, 곱셈인 경우, 나눗셈인 경우에 대해서 결과를 계산해서 넘겨준다.
        if(i == 0) {
            solve(index+1,op, result+num[index+1]);
        } else if(i == 1) {
            solve(index+1,op, result-num[index+1]);
        } else if(i == 2) {
            solve(index+1,op, result*num[index+1]);
        } else {
            solve(index+1,op, result/num[index+1]);
        }
 
        //i번째 연산자를 사용하는 경우를 위에서 보내줬으므로
        //다시 돌아왔을때 연산자의 상태를 원래대로 돌려준다.
        op[i] += 1;
    }
}
 
int main() {
    cin >> n;
 
    int op[4];
 
 
    //피연산자를 입력
    for(int i=0; i<n; i++) {
        int x;
        cin >> x;
        num.push_back(x);
    }
 
 
    //각 연산자의 개수를 입력
    for(int i=0; i<4; i++) {
        int x;
        cin >> x;
        op[i] = x;
    }
 
    solve(0,op, num[0]);
 
 
    //계산 결과를 정렬해준다.
    sort(ans.begin(), ans.end());
 
 
    //맨뒤의 값이 최댓값, 맨 앞의 값이 최소값이므로 각각 출력해준다.
    cout << ans.back() << '\n';
    cout << ans.front();
 
    return 0;
}
Colored by Color Scripter
 

'BOJ' 카테고리의 다른 글

[BOJ] 4963. 섬의 개수  (0) 2019.06.25
[BOJ] 2667. 단지번호붙이기  (0) 2019.06.25
[BOJ] 6603. 로또  (0) 2019.06.20
[BOJ] 10971. 외판원 순회2 (DFS 풀이)  (0) 2019.06.20
[BOJ] 10971. 외판원 순회2  (0) 2019.06.20

https://www.acmicpc.net/problem/6603

 

6603번: 로또

문제 독일 로또는 {1, 2, ..., 49}에서 수 6개를 고른다. 로또 번호를 선택하는데 사용되는 가장 유명한 전략은 49가지 수 중 k(k>6)개의 수를 골라 집합 S를 만든 다음 그 수만 가지고 번호를 선택하는 것이다. 예를 들어, k=8, S={1,2,3,5,8,13,21,34}인 경우 이 집합 S에서 수를 고를 수 있는 경우의 수는 총 28가지이다. ([1,2,3,5,8,13], [1,2,3,5,8,21], [1,2,3,5,8,34], [1,2

www.acmicpc.net

 

K개 중 6개를 고르는 문제이다. 고르는 개수가 정해져 있기 때문에 넥퍼뮤를 사용해도 좋지만 조합을 이용해서 구했다.

 

먼저 k개만큼 배열에 입력받고, 이 배열에서 6개를 고르는 모든 경우를 구해준다.

숫자를 고를때마다 lotto 벡터에 넣어주고 6개의 숫자를 고른 경우 lotto 벡터에 있는 값들을 모두 출력해주고 return

k개의 숫자를 사용할지 안 할지 모두 정한 경우(index 가 k를 넘어간 경우)에도 더 이상 고를 숫자가 없으므로 return 해준다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
 
int k;
int num[12];
 
void solve(int index, int select, vector<int> &lotto) {
    //고를 수의 범위가 넘어감
    if(index > k) {
        return;
    }
 
    //6개를 모두 골랐다
    if(select == 6) {
 
        //고른 숫자들을 모두 출력해준다.
        for(int i=0; i<6; i++) {
            cout << lotto[i] << ' ';
        }
        cout << '\n';
        return;
    }
 
 
    //현재 index번째 숫자를 고른 경우를 탐색.
    //하나를 골랐으므로 select 값을 1 증가시킨다.
    lotto.push_back(num[index]);
    solve(index+1, select+1, lotto);
 
    //다시 빼주고 고르지 않는 경우를 탐색
    lotto.pop_back();
    solve(index+1, select, lotto);
 
}
 
 
int main() {
 
    while(true) {
        cin >> k;
        if(k == 0break;
 
        for(int i=0; i<k; i++) {
           int x;
           cin >> x;
           num[i] = x;
        }
 
        vector<int> lotto;
        solve(0,0,lotto);
        cout << '\n';
    
    }
 
    return 0;
}
Colored by Color Scripter
 

 

'BOJ' 카테고리의 다른 글

[BOJ] 2667. 단지번호붙이기  (0) 2019.06.25
[BOJ] 14888. 연산자 끼워넣기  (0) 2019.06.20
[BOJ] 10971. 외판원 순회2 (DFS 풀이)  (0) 2019.06.20
[BOJ] 10971. 외판원 순회2  (0) 2019.06.20
[BOJ] 10974. 모든 순열  (0) 2019.06.20

https://www.acmicpc.net/problem/10971

 

10971번: 외판원 순회 2

첫째 줄에 도시의 수 N이 주어진다. (2 ≤ N ≤ 10) 다음 N개의 줄에는 비용 행렬이 주어진다. 각 행렬의 성분은 1,000,000 이하의 양의 정수이며, 갈 수 없는 경우는 0이 주어진다. W[i][j]는 도시 i에서 j로 가기 위한 비용을 나타낸다. 항상 순회할 수 있는 경우만 입력으로 주어진다.

www.acmicpc.net

앞에서 next_permutation을 사용해서 풀었는데 dfs를 사용해서도 풀어봤다.

개인적으로 아직 넥퍼뮤가 익숙하지 않아서 dfs로 푸는 게 더 풀기 쉬웠다.

 

dfs를 사용할때는 방문 표시를 잘해주면 된다.

현재 도시를 방문하는 경우 check배열을 true값으로 바꿔주고 현재 도시를 선택하는 경우를 모두 해준 경우(탐색에서 돌아온 경우)

방문 표시를 지워준다(false 값으로 바꿔준다)

 

자세한 설명은 아래 코드를 참고!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#include <iostream>
 
using namespace std;
int w[10][10];
int n;
int ans;
 
void dfs(int index,int cnt, int sum, bool check[]) {
 
    //첫번째 도시부터 마지막 도시까지 방문했으면
    if(cnt == n-1) {
 
        //마지막도시에서 시작 도시로 경로가 존재하지 않으면 return
        if(w[index][0== 0return;
        //그렇지 않으면 비용을 합에 더해준다.
        else sum += w[index][0];
 
        //최솟값이 초기값이거나 sum이 현재 최솟값보다 적은 경우
        if(ans == -1 || ans > sum) {
            ans = sum;
        }
 
        return;
    }
 
 
    //방문하지 않은 모든 도시로 가는 경우를 탐색
    for(int i=1; i<n; i++) {
 
        //i번째 도시를 방문했으면 넘어간다.
        if(check[i]) continue;
 
        //경로가 존재하지 않으면 넘어간다.
        if(w[index][i] == 0continue;
 
 
        //i번째 도시를 방문
        check[i] = true;
        dfs(i,cnt+1,sum+w[index][i],check);
 
        //i번째 도시를 가는 경우에서 돌아왔으므로 방문표시를 없애준다.
        check[i] = false;
 
    }
 
}
 
 
int main() {
    cin >> n;
 
 
    //비용을 w배열에 입력
    for(int i=0; i<n; i++) {
        for(int j=0; j<n; j++) {
            cin >> w[i][j];
        }
    }
 
 
    //최솟값을 저장
    ans = -1;
 
    //check 배열을 사용하여 방문 표시를 한다. false값으로 초기화
    bool check[10]={false};
 
    //0번째 도시를 시작점으로 잡고 탐색을 시작한다
    check[0= true;
    dfs(0,0,0,check);
 
    cout << ans;
    
    return 0;
}
Colored by Color Scripter
 

'BOJ' 카테고리의 다른 글

[BOJ] 14888. 연산자 끼워넣기  (0) 2019.06.20
[BOJ] 6603. 로또  (0) 2019.06.20
[BOJ] 10971. 외판원 순회2  (0) 2019.06.20
[BOJ] 10974. 모든 순열  (0) 2019.06.20
[BOJ] 9095. 1, 2, 3 더하기  (0) 2019.06.20

https://www.acmicpc.net/problem/10971

 

10971번: 외판원 순회 2

첫째 줄에 도시의 수 N이 주어진다. (2 ≤ N ≤ 10) 다음 N개의 줄에는 비용 행렬이 주어진다. 각 행렬의 성분은 1,000,000 이하의 양의 정수이며, 갈 수 없는 경우는 0이 주어진다. W[i][j]는 도시 i에서 j로 가기 위한 비용을 나타낸다. 항상 순회할 수 있는 경우만 입력으로 주어진다.

www.acmicpc.net

외판원 순회 문제는 영어로 Traveling Salesman problem (TSP)라고 불리는 문제로 computer science 분야에서 가장 중요하게 취급되는 문제 중 하나라고 문제 설명에 나와있다.

실제로 학교 알고리즘 수업에서도 배운 기억이 있다.

 

이 문제에서는 n의 범위가 (2 ≤ N ≤ 10) 이므로 다음 순열을 이용해서 모든 경로를 구해볼 수 있다.

모든 경로에서의 비용을 계산해서 최솟값을 구해준다.

다음 순열은 d 벡터를 만들어서 사용한다.

d벡터에는 n만큼의 수가 들어있다. 예를 들어, n 이 4이면 d에는 0, 1, 2, 3의 값이 들어 있고 각각은 도시를 의미한다.

이 d 벡터의 모든 순열을 구해줘서 모든 경로를 구할 수 있다.

즉, d 벡터의 값이 도시의 번호와 마찬가지이므로 d벡터의 값을 w배열의 index로 사용하면 된다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
 
int main() {
    int n;
    cin >> n;
    int w[10][10];
    vector<int> d(n);
 
    for(int i=0; i<n; i++) {
        for(int j=0; j<n; j++) {
            cin >> w[i][j];
        }
    }
 
    for(int i=0; i<n; i++) {
        d[i] = i;
    }
 
    int ans = -1;
 
 
    //모든 경로 탐색
    do {
        int sum = 0;
        bool ok = true;
 
 
        //첫 번째 도시부터 마지막 도시까지의 비용을 더해준다.
        for(int i=0; i<n-1; i++) {
 
            //비용이 0인 경우, 즉 경로가 존재하지 않는 경우에는 ok를 false로 바꿔주고 break
            if(w[d[i]][d[i+1]] == 0) {
                ok = false;
                break;
            }
 
            sum += w[d[i]][d[i+1]];
        }
 
 
        //위에서 모든 경로가 존재하고(ok == true), 다시 마지막 도시에서 첫 번재 도시로 경로가 존재하는 경우
        //sum에 마지막 도시에서 첫 번째 도시로 가는 비용을 더해주고 최소값과 비교해준다.
        if(ok && w[d[n-1]][d[0]] != 0) {
            sum += w[d[n-1]][d[0]];
            if(ans == -1 || ans > sum) {
                ans = sum;
            }
        }
 
    } while(next_permutation(d.begin(),d.end()));
 
    cout << ans;
 
    return 0;
}
Colored by Color Scripter
 

'BOJ' 카테고리의 다른 글

[BOJ] 6603. 로또  (0) 2019.06.20
[BOJ] 10971. 외판원 순회2 (DFS 풀이)  (0) 2019.06.20
[BOJ] 10974. 모든 순열  (0) 2019.06.20
[BOJ] 9095. 1, 2, 3 더하기  (0) 2019.06.20
[BOJ] 6588. 골드바흐의 추측  (0) 2019.06.18

https://www.acmicpc.net/problem/10974

 

10974번: 모든 순열

N이 주어졌을 때, 1부터 N까지의 수로 이루어진 순열을 사전순으로 출력하는 프로그램을 작성하시오.

www.acmicpc.net

N의 범위가 (1 ≤ N ≤ 8) 이므로 다음 순열을 구해서 모든 순열을 구할 수 있다.

java에서는 next permutaion함수를 직접 구현해줬어야 했는데

c++은 라이브러리가 있어서 좋다...ㅠㅠ

그냥 next_permutation을 써주면 된다...!!

 

next_permutation을 사용할 때는 do while로 사용해줘야 한다. 무조건 한 번은 실행되어야 하기 때문.

그리고 넥퍼뮤 돌릴 자료구조는 벡터를 사용한다.

넥퍼뮤 while문이 돌아갈 때마다 현재 배열을 순차적으로 출력해주면 끝!

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
 
int main() {
    int n;
    cin >> n;
    vector<int> a;
 
    for(int i=0; i<n; i++) {
        a.push_back(i+1);
    }
 
    do {
        for(int i=0; i<n; i++) {
            cout << a[i] << ' ';
        }
        cout << '\n';
    } while(next_permutation(a.begin(),a.end()));
 
    return 0;
}
Colored by Color Scripter

 

 

'BOJ' 카테고리의 다른 글

[BOJ] 10971. 외판원 순회2 (DFS 풀이)  (0) 2019.06.20
[BOJ] 10971. 외판원 순회2  (0) 2019.06.20
[BOJ] 9095. 1, 2, 3 더하기  (0) 2019.06.20
[BOJ] 6588. 골드바흐의 추측  (0) 2019.06.18
[BOJ] 2609. 최대공약수와 최소공배수  (0) 2019.06.14

https://www.acmicpc.net/problem/9095

 

9095번: 1, 2, 3 더하기

문제 정수 4를 1, 2, 3의 합으로 나타내는 방법은 총 7가지가 있다. 합을 나타낼 때는 수를 1개 이상 사용해야 한다. 1+1+1+1 1+1+2 1+2+1 2+1+1 2+2 1+3 3+1 정수 n이 주어졌을 때, n을 1, 2, 3의 합으로 나타내는 방법의 수를 구하는 프로그램을 작성하시오. 입력 첫째 줄에 테스트 케이스의 개수 T가 주어진다. 각 테스트 케이스는 한 줄로 이루어져 있고, 정수 n이 주어진다. n은 양수이며 11보다 작다. 출력 각

www.acmicpc.net

 

DP로 푸는 문제이긴 하지만 n이 11보다 작은 양수이기 때문에 완전 탐색으로도 풀어줄 수 있다.

방법의 수를 구하는 문제이므로, 1, 2, 3을 더한 경우를 모두 구해서 더한 값이 n이 될 때마다 ans 값을 증가시키고 return

n값을 넘어가버려도 return 해준다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>
using namespace std;
int ans;
 
void solve(int sum ,int n) {
    if(sum > n) return;
    if(sum == n) {
        ans++;
        return;
    }
 
    solve(sum+1,n);
    solve(sum+2,n);
    solve(sum+3,n);
 
}
 
int main() {
    int T;
    cin >> T;
     
    for(int tc=0; tc<T; tc++) {
        int n;
        cin >> n;
        ans = 0;
        solve(0, n);
        cout << ans << '\n';
    }
 
 
    return 0;
}
 

'BOJ' 카테고리의 다른 글

[BOJ] 10971. 외판원 순회2  (0) 2019.06.20
[BOJ] 10974. 모든 순열  (0) 2019.06.20
[BOJ] 6588. 골드바흐의 추측  (0) 2019.06.18
[BOJ] 2609. 최대공약수와 최소공배수  (0) 2019.06.14
[BOJ] 3055. 탈출  (0) 2019.05.01

https://www.acmicpc.net/problem/6588

 

6588번: 골드바흐의 추측

문제 1742년, 독일의 아마추어 수학가 크리스티안 골드바흐는 레온하르트 오일러에게 다음과 같은 추측을 제안하는 편지를 보냈다. 4보다 큰 모든 짝수는 두 홀수 소수의 합으로 나타낼 수 있다. 예를 들어 8은 3 + 5로 나타낼 수 있고, 3과 5는 모두 홀수인 소수이다. 또, 20 = 3 + 17 = 7 + 13, 42 = 5 + 37 = 11 + 31 = 13 + 29 = 19 + 23 이다. 이 추측은 아직도 해결되지 않은 문제이다. 백만 이하의 모

www.acmicpc.net

문제에서 n의 범위는 (6 ≤ n ≤ 1000000)이다.

골드바흐의 추측은 10의 18 제곱까지는 증명되었다고 하므로

두 홀수 소수의 합으로 n을 나타낼 수 없는 경우에 "Goldbach's conjecture is wrong."을 출력하라고 문제에 나와있지만

안 해줘도 될 것 같다.

 

소수는 에라토스테네스의 체를 이용해서 n의 범위만큼 미리 구해서 배열에 저장한다.

n이 두 소수 p와 q로 이루어져 있다고 했을 때,

p + q = n

n - p = q

이므로 n에서 소수를 뺀 값이 소수이면 답을 바로 출력한다.

 

참고로 c++에서

ios_base::sync_with_stdio(false);

cin.tie(nullptr);

를 써주면 입출력 속도를 높일 수 있다고 한다.

대신에 printf, scnaf 등은 사용하면 안 된다.

 

#include <iostream>
using namespace std;
const int MAX = 1000000;
int prime[MAX];
int cnt;
bool check[MAX+1];

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    
    //소수를 구해준다.
    for(int i=2; i*i<=MAX; i++) {
    	//이미 소수가 아닌걸로 체크되어 있는 경우
        if(check[i] == true) continue;

		//위의 조건에 걸리지 않았다면 소수이므로 소수 배열에 추가
        prime[cnt++] = i;
        
        //현재 소수의 배수들은 소수가 아니므로 체크해준다.
        for(int j=i+i; j<=MAX; j+=i) {
            check[j] = true;
        }

    }

    while(true) {
        int n;
        cin >> n;
        if(n == 0) break;
        for(int i=1; i<cnt; i++) {
            if(check[n-prime[i]] == false) {
                cout << n << " = " << prime[i] << " + " << n-prime[i] <<  "\n";
                break;

            }
        }
    }

    return 0;
}

'BOJ' 카테고리의 다른 글

[BOJ] 10974. 모든 순열  (0) 2019.06.20
[BOJ] 9095. 1, 2, 3 더하기  (0) 2019.06.20
[BOJ] 2609. 최대공약수와 최소공배수  (0) 2019.06.14
[BOJ] 3055. 탈출  (0) 2019.05.01
[BOJ] 2583. 영역 구하기  (0) 2019.05.01

https://www.acmicpc.net/problem/2609

 

2609번: 최대공약수와 최소공배수

첫째 줄에는 입력으로 주어진 두 수의 최대공약수를,둘째 줄에는 입력으로 주어진 두 수의 최소 공배수를 출력한다.

www.acmicpc.net

최대공약수는 유클리드 호제법을 사용한 gcd 함수를 사용한다.

gcd 함수는 아래 코드와 같이 구현하면 된다.

최소공배수는 a와 b를 곱한 값에 최대공약수로 나누어주면 구할 수 있다.

 

#include &ltiostream&gt
using namespace std;

//최대공약수를 구하는 함수
int gcd(int a, int b) {
    if(b== 0) return a;
    else return gcd(b, a%b);
}

int main() {
    int a, b;
    cin >> a >> b;
    
    int g = gcd(a,b);
    cout << g << '\n' << a*b/g << '\n';
    
    return 0;
}

'BOJ' 카테고리의 다른 글

[BOJ] 9095. 1, 2, 3 더하기  (0) 2019.06.20
[BOJ] 6588. 골드바흐의 추측  (0) 2019.06.18
[BOJ] 3055. 탈출  (0) 2019.05.01
[BOJ] 2583. 영역 구하기  (0) 2019.05.01
[BOJ] 2606. 바이러스  (0) 2019.05.01

+ Recent posts