Baekjoon

Baekjoon 9465번 스티커

ppwag 2020. 9. 9. 14:55

문제

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

걸린 시간

03 : 00 : 43 실패

시간 초과 풀이

C++

#include <bits/stdc++.h>
#define INF 987654321
using namespace std;

int n;
int plate[2][100001], visited[2][100001], cache[2][100001];

int dy[4] = {1, -1, 0, 0};
int dx[4] = {0, 0, -1, 1};

int dp(int r, int c){ // row, col
    // 기저 사례
    if(c == n)    
        return 0;
    // 메모이제이션
    int& ret = cache[r][c];
    if(ret != -1)
        return ret;
    // 재귀 호출
    for(int x = c+1; x <= n; x++){
        for(int y = 0; y < 2; y++){
            if(!visited[y][x]){
                vector<pair<int, int>> tmp;
                for(int i = 0; i < 4; i++){
                    int ny = y+dy[i];
                    int nx = x+dx[i];
                    if(!visited[ny][nx] && 0 <= ny && ny < 2 && 1 <= nx && nx <= n){
                        visited[ny][nx] = 1;
                        tmp.push_back(make_pair(ny, nx));
                    }
                }
                visited[y][x] = 1;
                ret = max(ret, dp(y, x)+plate[y][x]);
                for(int i = 0; i < tmp.size(); i++)
                    visited[tmp[i].first][tmp[i].second] = 0;    
                visited[y][x] = 0;
            }
        }
    }
    return ret;
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(NULL);
    int tc;
    cin >> tc;
    while(tc--){
        cin >> n;
        for(int i = 0; i < 2; i++)
            for(int j = 1; j <= n; j++)
                cin >> plate[i][j];
        memset(visited, 0, sizeof(visited));
        memset(cache, -1, sizeof(cache));
        cout << dp(0, 0) << "\n";
    }
    return 0;
}

규칙을 찾지 못해 모든 경우의 수에 메모이제이션을 적용한 풀이.

테스트 케이스의 개수와 반복문 속의 많은 연산으로 시간초과가 난 것으로 예상.

옳은 풀이

C++

#include <bits/stdc++.h>
#define INF 987654321
using namespace std;

int n;
int plate[2][100001], cache[2][100001];

int dp(int y, int x){
    // 기저 사례
    if(x > n) return 0;
    if(x == n) return plate[y][x];
    // 메모이제이션
    int& ret = cache[y][x];
    if(ret != -1)
        return ret;
    // 재귀 호출
    ret = max(ret, dp((y+1)%2, x+1)+plate[y][x]);
    ret = max(ret, dp((y+1)%2, x+2)+plate[y][x]);
    return ret;
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(NULL);
    int tc;
    cin >> tc;
    while(tc--){
        cin >> n;
        for(int i = 0; i < 2; i++)
            for(int j = 1; j <= n; j++)
                cin >> plate[i][j];
        memset(cache, -1, sizeof(cache));
        cout << max(dp(0, 0), dp(1, 0)) << "\n";
    }
    return 0;
}

맨 처음 스티커부터 차례로 떼어낸다고 했을 때 가능한 경우는 한 칸 앞 대각선, 두 칸 앞 대각선뿐인 규칙을 찾아내면 쉽게 풀이할 수 있다.

아직까지 메모이제이션을 적용하는 실력이 부족해서 많은 시행착오를 겪고있다. 올바른 캐쉬의 형태는 원본 데이터와 대부분 같다는 점을 기억하자.

'Baekjoon' 카테고리의 다른 글

Baekjoon 2206번 벽 부수고 이동하기  (0) 2020.09.10
Baekjoon 2293번 동전 1  (0) 2020.09.10
Baekjoon 11052번 카드 구매하기  (0) 2020.09.09
Baekjoon 1138번 한 줄로 서기  (0) 2020.09.08
Baekjoon 2631번 줄세우기  (0) 2020.09.08

댓글