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
//누적되는 부분합보다 새로운 수가 더 클 때 부분합을 다시 시작한다.
#include <iostream>
#include <algorithm>
long long d[100050];
int num[100050];
using namespace std;
int main()
{
    int input;
    cin >> input;
    for (int i = 1; i <= input; ++i)
    {
        cin >> num[i];
    }
    d[1] = num[1];
    for (int i = 1; i <= input; ++i)
    {
        d[i] = d[i - 1] + num[i];
        //새로 부분합을 시작하는 경우
        if (d[i] < num[i])
            d[i] = num[i];
    }
    long long ans = d[1];
    for (int i = 1; i <= input; ++i)
        ans = max(ans, d[i]);
    cout << ans << endl;
    return 0;
}
cs


가장 긴 증가하는 부분 순열과 비슷하지만 약간의 트릭으로 스택에 수열을 넣고 다시 빼놓아서 뒤집어주고 동일한 방법으로 가장 긴 증가하는 부분 순열을 구하면 된다. 스택에 들어간 일련의 원소들은 순서가 뒤집어주는 성질이 있다. 유용하게 사용하자

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
77
78
 
#include <iostream>
#include <algorithm> 
#include <stack>
using namespace std
int d[1050];
int seq[1050];
stack<int> make_reverse;
int main() 
{
    int input = 0;
    cin >> input;
    for (int i = 1; i <= input; ++i)
    {
        cin >> seq[i];
        make_reverse.push(seq[i]);
    }
    for (int i = 1; i <= input; ++i)
    {
      seq[i] = make_reverse.top();
        make_reverse.pop();
    }
    for (int i = 0; i <= input; ++i)
        d[i] = 1;
    for (int i = 2; i <= input; ++i)
    {
        for (int j = 1; j < i; ++j)
        {
            if (seq[i] > seq[i - j])
                d[i] = max(d[i], d[i - j] + 1);
        }
    }
    int ans = 0;
    for (int i = 1; i <= input; ++i)
        ans = max(ans, d[i]);
    cout << ans;
    return 0;
 
}
cs


'백준 온라인 저지' 카테고리의 다른 글

백준 13398: 연속합 2  (0) 2018.07.10
백준 1912: 연속합  (0) 2018.07.09
백준 11053: 가장 긴 증가하는 부분 순열  (0) 2018.07.09
백준 2156: 포도주 시식  (0) 2018.07.09
백준 9465: 스티커  (0) 2018.07.09

가장 긴 증가하는 부분 수열 문제, 다이나믹 프로그램을 활용하면 된다. 힌트는 해당 수열의 부분이 이전 수들과 대소 비교를 해서 그 중 가장 길었던 수열에 +1 해주면 되는 것!


#include <iostream>
#include <algorithm>
using namespace std;
int d[1050];
int seq[1050];
int main()
{
int input = 0;
cin >> input;
for (int i = 1; i <= input; ++i)
{
cin >> seq[i];
}
for (int i = 0; i <= input; ++i)
d[i] = 1;
for (int i = 2; i <= input; ++i)
{
for (int j = 1; j < i; ++j)
{
if (seq[i] > seq[i - j])
d[i] = max(d[i], d[i - j] + 1);
}
}
int ans = 0;
for (int i = 1; i <= input; ++i)
ans = max(ans, d[i]);
cout << ans;
return 0;
}


'백준 온라인 저지' 카테고리의 다른 글

백준 1912: 연속합  (0) 2018.07.09
백준 11722: 가장 긴 감소하는 부분 순열  (0) 2018.07.09
백준 2156: 포도주 시식  (0) 2018.07.09
백준 9465: 스티커  (0) 2018.07.09
백준 2193: 이친수  (0) 2018.07.09

다이나믹 프로그래밍을 활용하는 문제. d[i][j] 가 i번째 포도주가 j번연속으로 와인을 먹은 상태이고 a[i]는 i번째에 든 포도주의 양이라고 하면

d[i][0] = max(d[i -1][0], d[i - 1][1], d[i - 1][2])

d[i][1] = d[i - 1][0] + a[i]

d[i][1] = d[i - 1][1] + a[i] 

로 점화식을 세울 수 있다. 0번 연속 마셨다면 이전의 포도주 중 가장 많은 값이 들어가야겠고 한 번이면 이전에(i - 1)에서 0번 연속 먹었을 때 두 번이면 한 번 연속 먹었을 때 일 것이다. 백준님께 들은 강의에서 내가 생각하는 경우로 코딩하면 대부분 틀린다고 항상 규칙을 찾고 일반적인 경우를 생각해야된다고 말씀하셨다.


#include <iostream>
#include <algorithm>
using namespace std;
long long d[10050][3];
long long wine[10050];
int main()
{
int input = 0;
cin >> input;
for (int i = 1; i <= input; ++i)
{
cin >> wine[i];
}
d[0][0] = d[0][1] = d[0][2] = 0;
//d[i][0] 연속해서 마신 포도주 0잔 ...
for (int i = 1; i <= input; ++i)
{
d[i][0] = max(d[i - 1][0], max(d[i - 1][1], d[i - 1][2]));
d[i][1] = d[i - 1][0] + wine[i];
d[i][2] = d[i - 1][1] + wine[i];
}
long long ans = 0;
ans = max(d[input][0], max(d[input][1], d[input][2]));
cout << ans;
return 0;
}



다이나믹 프로그래밍을 이용하는 문제. 스티커를 뜯지 않았을 때, 위쪽을 뜯었을 때, 아래쪽을 뜯었을 때의 경우를 나누고 각 경우에 따라 이전의 스티커 상태와의 관계를 점화식으로 세운 후 코딩하면 된다. 마지막 출력에서 endl을 쓰지 않아서 답 찾느라고 고생했다.. 후 

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>
#include <algorithm>
using namespace std;
long long d[100100][3];
long long point[1000100][2];
 
int main()
{
    int init_input = 0;
    cin >> init_input;
    //주어진 T케이스 만큼 값을 구한다.
    while (init_input--)
    {
        int line = 0;
        cin >> line;
        //point 배열에 주어진 값 넣기
        for (int j = 0; j < 2++j)
        {
            for (int k = 1; k <= line; ++k)
                cin >> point[k][j];
        }
        //d[i][0] 안뜯었을 때의 값 d[i][1] 아래 스티커 뜯었을 때의 값 d[i][2] 위 스티커 뜯었을 때의 값
        d[0][0= 0;
        d[0][1= 0;
        d[0][2= 0;
        for (int j = 1; j <= line; ++j)
        {
            d[j][0= max(d[j - 1][0], max(d[j - 1][1], d[j - 1][2]));
            d[j][1= max(d[j - 1][0], d[j - 1][2]) + point[j][0];
            d[j][2= max(d[j - 1][0], d[j - 1][1]) + point[j][1];
        }
        long long ans = 0;
        for (int l = 1; l <= line; l++) {
            ans = max(max(ans, d[l][0]), max(d[l][1], d[l][2]));
        }
        cout << ans << endl; //출력을 잘보자..
    }
    return 0;
}
cs


'백준 온라인 저지' 카테고리의 다른 글

백준 11053: 가장 긴 증가하는 부분 순열  (0) 2018.07.09
백준 2156: 포도주 시식  (0) 2018.07.09
백준 2193: 이친수  (0) 2018.07.09
백준 11057: 오르막 수  (0) 2018.07.09
백준 10799: 쇠막대기  (0) 2018.07.09

이친 수 문제 1이 연속으로 나오지 않는 이진수를 말한다. 풀이는 상당히 쉽게 떠오르는데 다이나믹 프로그래밍을 사용하면 된다. 나는 강의를 듣고 있는지라 바로 다이나믹인 걸 알고 있으나.. 그렇지 않아도 충분히 떠오를만 하다. 일단 이친수의 자리 수를 n이라고 하면 끝이 0으로 끝나면 d[n]0]에 1로 끝나면 d[n][1]에 저장하면 d[n][i] += d[n -1][k] (k는 0일 때는 i가 0, 1 둘 다 더해주고 1일 때는 0 부분에만 더해주면 되겠다.) 같은 점화식으로 표현할 수 있다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
using namespace std;
int input = 0;
long long d[100][2];
int main()
{
    cin >> input;
    d[1][0= 0;
    d[1][1= 1;
    for(int i = 2;i <= input; ++i)
    {
        d[i][1+= d[i - 1][0];
        d[i][0+= d[i - 1][1];
        d[i][0+= d[i - 1][0];
    }
    long long ans = d[input][0+ d[input][1];
    cout << ans;
}
cs

 

'백준 온라인 저지' 카테고리의 다른 글

백준 11053: 가장 긴 증가하는 부분 순열  (0) 2018.07.09
백준 2156: 포도주 시식  (0) 2018.07.09
백준 9465: 스티커  (0) 2018.07.09
백준 11057: 오르막 수  (0) 2018.07.09
백준 10799: 쇠막대기  (0) 2018.07.09

다이나믹 프로그래밍을 이용해서 푸는 문제 자리 수가 i이고 자리 수의 마지막 수가 j라고 하면 d[i][j] 라는 식으로 표현하고

이는 d[i][j] += d[i -1][k] (0 <= k<= j) 점화식으로 확장 될 수 있다. 잘 생각해보면 예를들어 마지막 수가 8이면 마지막 수가 0부터 8까지 전 자리 수의 개수를 더해주면 된다. 3중 for문이라 좀 당황했는데 n에 따라 변하지는 않으므로 복잡도는 O(n)이라고 볼 수 있을 것 같다.


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
#include <iostream>
using namespace std;
int input = 0;
long long d[1050][15];
int main()
{
    cin >> input;
    for(int i = 0;i < 10++i)
        d[1][i] = 1;
    for(int i = 2; i <= input; ++i)
    {
        for(int j = 0;j <= 9++j)
        {
            for(int k = 0;k <= j; ++k)
            {
                d[i][j] += d[i - 1][k];
                d[i][j] %= 10007;
            }
        }
    }
    long long ans = 0;
    for(int i = 0;i < 10++i)
    {
        ans += d[input][i];
        ans %= 10007;
    }
    cout << ans;
    return 0;
}
cs


'백준 온라인 저지' 카테고리의 다른 글

백준 11053: 가장 긴 증가하는 부분 순열  (0) 2018.07.09
백준 2156: 포도주 시식  (0) 2018.07.09
백준 9465: 스티커  (0) 2018.07.09
백준 2193: 이친수  (0) 2018.07.09
백준 10799: 쇠막대기  (0) 2018.07.09

10799번 쇠막대 문제는 스택을 이용해서 풀면 쉽게 풀 수 있지만 레이저와 쇠막대의 관해서 조금 생각해 볼 필요가 있다.

비슷한 문제로는 9012번 괄호문제도 있다. 괄호문제는 뭔가 코드가 더럽게 나온거 같은데 쇠막대 문제는 논리구조가 깔끔해서 오히려 더 맘에 드는 문제이다. 쇠막대와 레이저간의 관계만 파악하면 쉽게 코드를 작성할 수 있는데 쉽게 말해 레이저가 쏘아질 때 지금까지 스택에 쌓여 있는 괄호가 쇠막대라고 생각하면 된다. 스택에 쌓여 있는 괄호만큼 레이저로 인해 쇠막대가 분리 되고 이 괄호들이 팝될 때 나머지 분리된 쇠막대가 추가 된다고 생각하면 쉽다. 



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
#include <iostream>
#include <stack>
#include <string>
using namespace std;
char a = '(';
stack<char> vpn_chk;
string vpn;
long long iron = 0;
bool recent = 0;
int main()
{
    cin >> vpn;
    int len = vpn.length();
    for (int i = 0; i < len; ++i)
    {
        char chk = vpn[i];
        if (chk == a){
            vpn_chk.push(vpn[i]);
            recent = true;
        }
        //pop 될 경우 레이저인 경우와 아닌 경우로 나뉜다.
        else
        {
            vpn_chk.pop();
            if (recent == true)
            {
                iron += vpn_chk.size();
                recent = false;
            }
            else
            {
                ++iron;
            }
        }
    }
    cout << iron;
    return 0;
}
cs



'백준 온라인 저지' 카테고리의 다른 글

백준 11053: 가장 긴 증가하는 부분 순열  (0) 2018.07.09
백준 2156: 포도주 시식  (0) 2018.07.09
백준 9465: 스티커  (0) 2018.07.09
백준 2193: 이친수  (0) 2018.07.09
백준 11057: 오르막 수  (0) 2018.07.09

+ Recent posts