Works Applications2016校園招聘 — Game

Problem


Jeff loves playing games, Gluttonous snake( an old game in NOKIA era ) is one of his favourites. However, after playing gluttonous snake so many times, he finally got bored with the original rules.

In order to bring new challenge to this old game, Jeff introduced new rules :

  1. The ground is a grid, with n rows and m columns(1 <= n, m <= 500).
  2. Each cell contains a value v (-1 ≤ vi≤  99999), if v is -1, then this cell is blocked, and the snake can not go through, otherwise, after the snake visited this cell, you can get v point.
  3. The snake can start from any cell along the left border of this ground and travel until it finally stops at one cell in the right border.
  4. During this trip, the snake can only go up/down/right, and can visit each cell only once.

Special cases :

  1. Even in the left border and right border, the snake can go up and down
  2. When the snake is at the top cell of one column, it can still go up, which demands the player to pay all current points , then the snake will be teleported to the bottom cell of this column and vice versa.

After creating such a new game, Jeff is confused how to get the highest score. Please help him to write a program to solve this problem.

Input

The first line contains two integers n (rows) and m (columns), (1 <= n, m <= 500), separated by a single space.

Next n lines describe the grid. Each line contains m integers vi (-1 ≤ vi ≤ 99999) vi = -1 means the cell is blocked.

Output

Output the highest score you can get. If the snake can not reach the right side, output -1.

Sample Test


input

4 4
-1 4 5 1
2 -1 2 4
3 3 -1 3
4 2 1 2
4 4
-1 4 5 1
2 -1 2 4
3 3 -1 -1
4 2 1 2

output

23
16

Solution 1


思路

直接使用回溯法,用grid[m][n]表示每個點的值,用vis[m][n]表示每個點是否訪問。該方法比較簡單直觀,不做多說。

代碼

#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cmath>
#include <map>
#include <algorithm>
using namespace std;

int grid[501][501];
bool vis[501][501];
int m, n;
long long ans = -1;
int cx[] = {-1, 0, 1};
int cy[] = {0, 1, 0};

void dfs(long long sum, int x, int y) {
    if (y == n - 1 && sum > ans) {
        ans = sum;
    }

    for (int i = 0; i < 3; ++i) {
        bool flag = false;
        int nx = x + cx[i];
        if (nx == -1) {
            nx = m - 1;
            flag = true;
        }
        if (nx == m) {
            nx = 0;
            flag = true;
        }
        int ny = y + cy[i];
        if (ny == n) continue;
        if (vis[nx][ny] || grid[nx][ny] == -1) continue;
        vis[nx][ny] = true;
        if (flag)
            dfs(grid[nx][ny], nx, ny);
        else
            dfs(sum + grid[nx][ny], nx, ny);
        vis[nx][ny] = false;
    }
}

int main() {
    scanf("%d%d", &m, &n);
    for (int i = 0; i < m; ++i)
        for (int j = 0; j < n; ++j)
            scanf("%d", &grid[i][j]);
    memset(vis, false, sizeof(vis));

    for (int i = 0; i < m; ++i) {
        if (grid[i][0] == -1)
            continue;
        vis[i][0] = true;
        dfs(grid[i][0], i, 0);
        vis[i][0] = false;
    }
    printf("%lld\n", ans);
    return 0;
}

Solution 2


思路

使用回溯法,雖然簡單容易理解,但是數據量太大容易爆棧。這題還可以使用動態規劃求解。使用grid[m][n]表示每個點的值,使用dp[0][i][j]表示從點[i, j]爲起點不穿越取得的最大值,dp[1][i][j]表示從點[i, j]爲起點有穿越取得的最大值。那麼狀態轉移方程爲:
當在j列不穿越:
dp[0][i][j] = max(dp[0][k][j + 1] + sumk)
dp[1][i][j] = max(dp[1][k][j + 1])
當在j列有穿越:
dp[1][i][j] = max(dp[0][k][j + 1] + sumk’)
dp[1][i][j] = max(dp[1][k][j + 1])
上面的轉移方程沒有考慮特殊情況。
有點複雜,可能看不大懂,還是直接上代碼吧,看代碼註釋應該容易懂很多。

代碼

#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cmath>
#include <map>
#include <algorithm>
using namespace std;

int grid[501][501];
long long dp[2][501][501];
//dp[0][i][j]表示從[i, j]點開始不穿越能取到的最大值
//dp[1][i][j]表示從[i, j]點開始穿越能取到的最大值
int m, n;

int main() {
    scanf("%d%d", &m, &n);
    for (int i = 0; i < m; ++i)
        for (int j = 0; j < n; ++j)
            scanf("%d", &grid[i][j]);

    memset(dp, 0, sizeof(dp));

    long long sum, ans1, ans2;
    bool flag;
    for (int j = n - 1; j >= 0; --j) {
        for (int i = 0; i < m; ++i) {
            sum = 0;
            if (grid[i][j] == -1) {
                //該點不可到達
                dp[0][i][j] = dp[1][i][j] = -1;
                continue;
            }
            ans1 = -1;  //記錄不穿越的最大值
            ans2 = -1;  //記錄穿越的最大值
            flag = false;   //記錄是否碰到不可到達的點
            //往上走
            for (int k = i; k >= 0; --k) {
                if (grid[k][j] == -1) {
                    flag = true;
                    break;
                }
                sum += grid[k][j];
                //在當前列未穿越
                if (dp[0][k][j + 1] != -1 && dp[0][k][j + 1] + sum > ans1)
                    ans1 = dp[0][k][j + 1] + sum;
                //如果取後面的穿越最大值,那麼前面的sum全部清0
                if (dp[1][k][j + 1] != -1 && dp[1][k][j + 1] > ans2)
                    ans2 = dp[1][k][j + 1];
            }
            if (!flag) {
                sum = 0;
                for (int k = m - 1; k > i; --k) {
                    if (grid[k][j] == -1) {
                        flag = true;
                        break;
                    }
                    sum += grid[k][j];
                    //在當前列有穿越
                    if (dp[0][k][j + 1] != -1 && dp[0][k][j + 1] + sum > ans2)
                        ans2 = dp[0][k][j + 1] + sum;
                    if (dp[1][k][j + 1] != -1 && dp[1][k][j + 1] > ans2)
                        ans2 = dp[1][k][j + 1];
                }
            }

            //往下走
            sum = 0;
            flag = false;
            for (int k = i; k < m; ++k) {
                if (grid[k][j] == -1) {
                    flag = true;
                    break;
                }
                sum += grid[k][j];
                if (dp[0][k][j + 1] != -1 && dp[0][k][j + 1] + sum > ans1)
                    ans1 = dp[0][k][j + 1] + sum;
                if (dp[1][k][j + 1] != -1 && dp[1][k][j + 1] > ans2)
                    ans2 = dp[1][k][j + 1];
            }
            if (!flag) {
                sum = 0;
                for (int k = 0; k < i; ++k) {
                    if (grid[k][j] == -1) {
                        flag = true;
                        break;
                    }
                    sum += grid[k][j];
                    if (dp[0][k][j + 1] != -1 && dp[0][k][j + 1] + sum > ans2)
                        ans2 = dp[0][k][j + 1] + sum;
                    if (dp[1][k][j + 1] != -1 && dp[1][k][j + 1] > ans2)
                        ans2 = dp[1][k][j + 1];
                }
            }

            dp[0][i][j] = ans1;
            dp[1][i][j] = ans2;
        }
    }

    //查詢最大值
    long long ans = -1;
    for (int i = 0; i < m; ++i) {
        if (dp[0][i][0] > ans)
            ans = dp[0][i][0];
        if (dp[1][i][0] > ans)
            ans = dp[1][i][0];
    }

    printf("%lld\n", ans);
    return 0;
}
發佈了88 篇原創文章 · 獲贊 91 · 訪問量 108萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章