bfs 문제를 dp로 풀었는데 채점에서 계속 탈락합니다.

  • yyjjang9
    yyjjang9

    dfs로 푸는 문제를 dp로 풀어보았습니다. 하지만 채점에서 계속 탈락해서 질문을 올립니다.

    <문제>
    https://www.acmicpc.net/problem/1600

    *코드 구성
    코드는 리컬시브하게 원숭이가 움직일 때 가능한지 고려하여 갈 수 있는 모든 방향의 경우의 수(12가지 또는 4가지)를 조사하면서 들어가고, 갈 곳이 없을 경우 리턴합니다.
    메모이제이션을 사용하는 것은 cache 3차원 배열을 이용합니다. 그 이유는 현재 위치(행,열)와 현재 남아잇는 점프 횟수가 합쳐져 하나의 경우의 수가 되기 때문입니다.
    틀린 답이 나오는 테스트 케이스라도 알고 싶습니다.

    #include <iostream>
    #include <string.h>
    
    using namespace std;
    enum{y,x};
    
    int k;
    int w, h;
    int cache[201][201][31];
    int map[213][213];
    int dir_ord[4][2] = { { 1,0 },{ -1,0 },{ 0,1 },{ 0,-1 }, };
    int dir_hor[8][2] = { { 1,2 },{ -1,2 },{ 1,-2 },{ -1,-2 },{ 2,1 },{ -2,1 },{ 2,-1 },{ -2,-1 } };
    
    int min(int a, int b) {
        return (a < b ? a : b);
    }
    
    int find1(int _y, int _x, int k) {
    
        if (_y == h-1 && _x == w-1) return 0;
    
        int& ret = cache[_y][_x][k];
        if (ret != -1) return ret;
    
        int temp = h*w;
    
        map[_y][_x] = 1;
    
        if (k > 0) {
            for (int i = 0; i < 8; i++) {
                int next_y = _y + dir_hor[i][y];
                int next_x = _x + dir_hor[i][x];
    
                if (next_y < 0 || next_y >= h || next_x < 0 || next_x >= w) continue;
                if (map[next_y][next_x] == 0) {
                    temp = min(temp, find1(next_y, next_x, k - 1) + 1);
                }
            }
        }
    
        for (int i = 0; i < 4; i++) {
            int next_y = _y + dir_ord[i][y];
            int next_x = _x + dir_ord[i][x];
    
            if (next_y < 0 || next_y >= h || next_x < 0 || next_x >= w) continue;
            if (map[next_y][next_x] == 0) {
                temp = min(temp, find1(next_y, next_x, k) + 1);
            }
        }
    
        map[_y][_x] = 0;
        ret = temp;
        return temp;
    }
    
    int main(void) {
    
        memset(cache, -1, sizeof(cache));
    
        cin >> k >> w >> h;
    
        for (int i = 0; i < h; i++) { for (int j = 0; j < w; j++) { scanf("%d", &map[i][j]); } }
    
    
        int answer = find1(0, 0, k);
    
        if (answer >= w*h || map[0][0] == 1) cout << -1 << endl;
        else cout << answer << endl;
    
    
    }
    

    6년 전
3개의 댓글이 있습니다.
  • keith
    keith

    소스를 정확히 훑어보진 않았지만, 애초에 DFS로 해결하면 안되는 문제 아닌가요? DP로 풀수 있는 문제는 맞는거 같습니다만,
    애초의 Approach가 BFS가 되어야 한다고 봅니다. (가능한 것을 찾을게 아니라 최소를 찾아야 하는데...) DFS는 애초에 최소값을 보장하진 않을텐데요?


    6년 전 link
  • keith
    keith

    DFS 자체로도 가능한 모든해를 다 찾아서 그중 최소값을 찾는다면 가능하겠지만, 아시다시피 비효율적이죠,
    주석이 없어서 자세히는 못봤지만 훑어 보니, 한 지점을 지나는데 해당 지점에서 DFS로 가능해를 찾으면, 그보다 더 좋은 해가 있음에도 불구하고, 메모해버리는 바람에, 다음에 그 영역에 들어가는 재귀에서 더이상 더 좋은 해를 찾으려는 노력을 안하는게 문제 같은데요?


    6년 전 link
  • keith
    keith

    잘 알고 계시겠지만, 비효율 적인 순서대로
    1. DFS로 모든 해를 다 찾아서 그 중, 가장 작은 값을 리턴한다.
    2. DFS기반의 B&B로, 지금까지 찾은 최소해 깊이 이상 들어가려는 재귀함수를 막아서 효율을 높인다.
    3. 메모이제이션에 기반한 BFS를 사용한다. (matrix에 depth 최소값 저장)
    (단순한 DP로는 점화식이 Linear 하지 않아서 힘들것 같습니다. 멀어졌다 다시 가까워지는게 최적해일 가능성이 있거든요)
    도움이 되었길 바래봅니다.


    6년 전 link
  • 정회원 권한이 있어야 커멘트를 다실 수 있습니다. 정회원이 되시려면 온라인 저지에서 5문제 이상을 푸시고, 가입 후 7일 이상이 지나셔야 합니다. 현재 문제를 푸셨습니다.