#문제

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

 

#작성 코드

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
#include <iostream>
#include <vector>
using namespace std;
 
int n, M;
vector<int> mem;
vector<int> cost;
int d[10001]; 
    // d[cost]에 cost를 만족하는 최대로 확보 가능한 메모리 크기를 저장한다. 
 
int main(){
    // 입 력 
    cin>>n>>M;
    for(int i=0; i<n; i++){
        int m;
        cin>>m;
        mem.push_back(m);
    }
    for(int i=0; i<n; i++){
        int c;
        cin>>c;
        cost.push_back(c);
    }
    // d배열 값을 모두 -1로 초기화
    fill_n(d, 10001-1); 
    
    // 필요한 메모리 M바이트를 확보하기 위한 앱 비활성화의 최소비용 계산.
    for(int i=0; i<n; i++){
        int c = cost[i];
        for(int j=10000; j>=c; j--){
            if( d[j-c]==-1 ) continue;    // 계산된적있는 j-c에 대해서만 계산 
            d[j] = max(d[j], d[j-c]+mem[i]);
            // i번째 app을 포함하는 경우와 포함하지 않는 경우 중 확보 메모리가 더 큰 경우 저장. 
        }
        if( d[c]<mem[i] ) d[c] = mem[i];
    }
    for(int i=0; i<10001; i++){
        if( d[i] >= M ){
        // 작은 cost부터 탐색, 최초로 확보 메모리가 M 이상인 경우 cost 출력 
            cout<<i<<'\n';
            return 0;
        }
    }
}
cs

##

메모리 확보를 위한 앱 비활성화는 1회만 가능하기 때문에(4781번 사탕가게 문제처럼 한 종류의 사탕을 여러번 사는 것이 불가능.)

for(int j=10000; j>=c; j--){} 와 같이 cost를 역순으로 줄여나가며 메모이제이션을 수행한다.

#문제

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

 

1520번: 내리막 길

첫째 줄에는 지도의 세로의 크기 M과 가로의 크기 N이 빈칸을 사이에 두고 주어진다. 이어 다음 M개 줄에 걸쳐 한 줄에 N개씩 위에서부터 차례로 각 지점의 높이가 빈 칸을 사이에 두고 주어진다. M과 N은 각각 500이하의 자연수이고, 각 지점의 높이는 10000이하의 자연수이다.

www.acmicpc.net

 

#작성 코드

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
#include <iostream>
using namespace std;
 
int m, n;
// map과 dp배열 (1,1) ~ (m,n) 사용 
int map[501][501];
int dp[501][501];
int d[4][2= {{-1,0}, {1,0}, {0,-1}, {0,1}};
 
bool isIn(int x, int y){
    return x>=1&&x<=m&&y>=1&&y<=n;
}
 
int downhill(int x, int y){
    if( dp[x][y]!=-1 ) return dp[x][y];    // 이미 계산한 적 있다면 그 값 리턴 
    if!isIn(x, y)) return 0;            // 범위를 벗어났다면 그 곳까지 가는 경우의 수는 0이다 
    if( x==1 && y==1 ) return 1;        //(1,1)에서 출발해서 (1,1)에 도착하는 경우의 수 : 1 
    
    dp[x][y] = 0;        // dp를 새로 계산할 때는 0으로 초기화하고 더해야한다. 
     
    for(int di=0; di<4; di++){
        // (x,y)의 상하좌우 탐색 
        int nextX = x+d[di][0];
        int nextY = y+d[di][1];
        // (x,y)보다 (nextX,nextY)의 높이가 높다면
        // (x,y)까지 가는 경우의 수 += 각 (nextX,nextY)까지 가는 경우의 수 
        if( map[nextX][nextY] > map[x][y] ){
            dp[x][y] += downhill(nextX, nextY);
        }
    }
    // 계산된 (x,y)까지 가는 경우의 수를 리턴한다. 
    return dp[x][y];    
}
int main(){
    cin>>m>>n;
    for(int i=1; i<=m; i++){
        for(int j=1; j<=n; j++){
            cin>>map[i][j];
            dp[i][j]=-1;    // dp배열 -1로 초기화. 
        }
    }
    cout<<downhill(m,n)<<'\n';
    return 0;
}
cs

##

bfs로 할 수 있을까? 하다가 dfs로 시도해보았다.

' (x,y)까지 가는 경우의 수 : (x,y)상하좌우 중에서 그보다 높이가 높은 곳까지 가는 경우의 수의 합 ' 이 부분이 가장 중요한 부분이다.

dp를 이용해서 한번 계산한 경우의 수에 대해서는 그 값을 그대로 불러와서 다시 계산하지 않도록 하였다.

'BOJ' 카테고리의 다른 글

BOJ 4781번 :: 사탕가게  (0) 2020.01.23
BOJ 7579번 :: 앱  (0) 2020.01.23
BOJ 12015번 :: 가장 긴 증가하는 부분 수열 2  (0) 2020.01.06
BOJ 11055번 :: 가장 큰 증가 부분 수열  (0) 2020.01.06
BOJ 11049번 :: 행렬 곱셈 순서  (0) 2020.01.06

#문제

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

 

12015번: 가장 긴 증가하는 부분 수열 2

첫째 줄에 수열 A의 크기 N (1 ≤ N ≤ 1,000,000)이 주어진다. 둘째 줄에는 수열 A를 이루고 있는 Ai가 주어진다. (1 ≤ Ai ≤ 1,000,000)

www.acmicpc.net

 

#작성 코드

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
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
 
int n;
int serial[1000001];
vector<int> asc;
 
int main(){
    cin>>n;
    for(int i=1; i<=n; i++){
        cin>>serial[i];
    }
    
    for(int i=1; i<=n; i++){
        if( asc.empty() ){
            asc.push_back(serial[i]);
            continue;
        }
        else{
            if( asc.back() < serial[i] ){
                asc.push_back(serial[i]);
                continue;
            }
            else{
                vector<int>::iterator iter = lower_bound(asc.begin(), asc.end(), serial[i]);
                *iter = serial[i];
                // asc에서 serial[i]보다 최초로 큰 원소를 찾고, serial[i]로 대체한다. 
                continue
            }
        }
    }
    cout<<asc.size()<<'\n';
    return 0;
}
cs

##

이분탐색으로 어떻게 푸는 것이 좋을지 전혀 떠오르지 않아서

https://ferrante.tistory.com/54, https://mygumi.tistory.com/303?category=677288 참고하여 이분탐색으로 푸는 방법을 공부했다.

 

lower_bound 함수와 upper_bound 함수는 <algorithm> 헤더파일에 포함되어 있는 함수.

https://okayoki2484.tistory.com/135

 

BOJ 10816번 :: 숫자 카드 2

#문제 https://www.acmicpc.net/problem/10816 10816번: 숫자 카드 2 첫째 줄에 상근이가 가지고 있는 숫자 카드의 개수 N(1 ≤ N ≤ 500,000)이가 주어진다. 둘째 줄에는 숫자 카드에 적혀있는 정수가 주어진..

okayoki2484.tistory.com

 

'BOJ' 카테고리의 다른 글

BOJ 7579번 :: 앱  (0) 2020.01.23
BOJ 1520번 :: 내리막 길  (0) 2020.01.09
BOJ 11055번 :: 가장 큰 증가 부분 수열  (0) 2020.01.06
BOJ 11049번 :: 행렬 곱셈 순서  (0) 2020.01.06
BOJ 2193번 :: 이친수  (0) 2020.01.05

#문제

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

 

11055번: 가장 큰 증가 부분 수열

수열 A가 주어졌을 때, 그 수열의 증가 부분 수열 중에서 합이 가장 큰 것을 구하는 프로그램을 작성하시오. 예를 들어, 수열 A = {1, 100, 2, 50, 60, 3, 5, 6, 7, 8} 인 경우에 합이 가장 큰 증가 부분 수열은 A = {1, 100, 2, 50, 60, 3, 5, 6, 7, 8} 이고, 합은 113이다.

www.acmicpc.net

 

#작성 코드

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
#include <iostream>
using namespace std;
 
int n;
int serial[1001];
int partsum[1001];
// 인덱스 1~min(1000, n)까지 사용. 
 
int main(){
    // 입력 및 초기화 
    cin>>n;
    for(int i=1; i<=n; i++)
        cin>>serial[i];
        
    partsum[1= serial[1];
    int partsumMax=partsum[1];
    
    // 가장 긴 증가하는 부분수열의 합 구하기 
    for(int i=2; i<=n; i++){
        partsum[i] = serial[i];        // 본인만 포함하는 가장 작은 케이스에서 시작. 
        for(int j=1; j<=i; j++){
            if( serial[i]>serial[j] && partsum[j]+serial[i] > partsum[i]){
                partsum[i] = partsum[j] + serial[i];
            }
        }
        partsumMax = max(partsumMax, partsum[i]); 
    }
    cout<<partsumMax<<'\n';
    return 0;
}
cs

##

LIS를 복습하며 비슷한 문제를 풀어보았다.

 

나를 포함하는 증가수열 중에서 증가수열 원소의 합이 최대가 될 때를 partsum[]에 저장한다.

'BOJ' 카테고리의 다른 글

BOJ 1520번 :: 내리막 길  (0) 2020.01.09
BOJ 12015번 :: 가장 긴 증가하는 부분 수열 2  (0) 2020.01.06
BOJ 11049번 :: 행렬 곱셈 순서  (0) 2020.01.06
BOJ 2193번 :: 이친수  (0) 2020.01.05
BOJ 11057번 :: 오르막 수  (0) 2020.01.05

#문제

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

 

11049번: 행렬 곱셈 순서

첫째 줄에 입력으로 주어진 행렬을 곱하는데 필요한 곱셈 연산의 최솟값을 출력한다. 정답은 231-1 보다 작거나 같은 자연수이다. 또한, 최악의 순서로 연산해도 연산 횟수가 231-1보다 작거나 같다.

www.acmicpc.net

 

#작성 코드

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
#include <iostream>
using namespace std;
 
int n;
int mat[501][2];
int INF = 987654321;
int dp[501][501];
 
int calMin(int s, int e){
    if( dp[s][e]!=INF )
        return dp[s][e];
    if( s==e )
        return dp[s][e]=0;
    if( s+1 == e )
        return dp[s][e] = mat[s][0]*mat[s][1]*mat[e][1];
    
    for(int mid=s; mid<e; mid++){
        int left = calMin(s, mid);
        int right = calMin(mid+1, e);
        dp[s][e] = min(dp[s][e], (left+right)+(mat[s][0]*mat[mid][1]*mat[e][1]));
    }
    return dp[s][e];
}
 
int main(){
    cin>>n;
    for(int i=1; i<=n; i++){
        cin>>mat[i][0]>>mat[i][1];
    }
    // dp배열 INF로 초기화 
    for(int i=0; i<501; i++){
        for(int j=0; j<501; j++){
            dp[i][j] = INF;
        }
    }
    
    cout<<calMin(1, n)<<'\n';
    return 0;
}
cs

##

11066번 파일 합치기 문제와 비슷!

#문제

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

 

2193번: 이친수

0과 1로만 이루어진 수를 이진수라 한다. 이러한 이진수 중 특별한 성질을 갖는 것들이 있는데, 이들을 이친수(pinary number)라 한다. 이친수는 다음의 성질을 만족한다. 이친수는 0으로 시작하지 않는다. 이친수에서는 1이 두 번 연속으로 나타나지 않는다. 즉, 11을 부분 문자열로 갖지 않는다. 예를 들면 1, 10, 100, 101, 1000, 1001 등이 이친수가 된다. 하지만 0010101이나 101101은 각각 1, 2번 규칙에 위배되

www.acmicpc.net

 

#작성 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
using namespace std;
 
int n;
long long int pn[91][2];
// pn[i][0] : i자리 이친수. 0으로 끝나는것 개수
// pn[i][1] : i자리 이친수. 1으로 끝나는것 개수
 
int main(){
    cin>>n;
    pn[1][0= 0;
    pn[1][1= 1;
    
    for(int i=2; i<=n; i++){
        pn[i][0= pn[i-1][0+ pn[i-1][1];
        pn[i][1= pn[i-1][0];
    }
    cout<<pn[n][0]+pn[n][1]<<'\n';
    return 0;
cs

##

처음 제출했을 때 틀렸습니다 판정을 받았는데, n의 최대값인 90을 넣어보니 -값이 출력되었다.

-> int형에는 90자리수의 이친수 개수를 다 담을 수 없다.

=> long long int 형으로 pn배열을 선언해주었더니 AC판정을 받았다.

'BOJ' 카테고리의 다른 글

BOJ 11055번 :: 가장 큰 증가 부분 수열  (0) 2020.01.06
BOJ 11049번 :: 행렬 곱셈 순서  (0) 2020.01.06
BOJ 11057번 :: 오르막 수  (0) 2020.01.05
BOJ 9095번 :: 1, 2, 3 더하기  (0) 2020.01.05
BOJ 11066번 :: 파일 합치기  (0) 2020.01.04

+ Recent posts