Works Applications2016校园招聘 — Game

来源:互联网 发布:淘宝北卡大学是正品吗 编辑:程序博客网 时间:2024/04/29 18:02

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;}
0 0
原创粉丝点击