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 :
- The ground is a grid, with n rows and m columns(1 <= n, m <= 500).
- 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.
- 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.
- During this trip, the snake can only go up/down/right, and can visit each cell only once.
Special cases :
- Even in the left border and right border, the snake can go up and down
- 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;}
- Works Applications2016校园招聘 — Game
- Works Applications2016校园招聘 — Travel Information Center
- 校园招聘
- 校园招聘
- 2014 阿里巴巴校园招聘笔试—南京
- 校园招聘会
- 金山校园招聘会
- IBM校园招聘
- 淘宝 校园招聘题目
- 校园招聘(笔试)
- 校园招聘(机试)
- 校园招聘(面试)
- 校园招聘面试杂谈
- Thoughtworks 2010 校园招聘
- google2011校园招聘
- 校园招聘感想
- 校园招聘“总结”
- 校园招聘 - 面试指南
- Learning Spark - LIGHTNING-FAST DATA ANALYSIS 第三章 - (3)
- IOS 9 关于微信,QQ三方登陆的https适配结局方案,XCODE配置
- 【思想感悟】——如何激发自己的正能量
- 基于struts框架的文件上传
- JAVA_SE基础——32.this关键字调用本类的构造方法
- Works Applications2016校园招聘 — Game
- 八分钟诠释什么是万向节死锁(Gimbal Lock)
- Python 安装boto boto3
- 开始自己的技术博客生涯
- 瞬时动作的函数
- Android应用setContentView与LayoutInflater加载解析机制源码分析
- js的数据类型
- 二
- 虚函数表指针的详细辨析