我通过递归来解决这个问题需要一些帮助。
问题:
一个懒惰的游客希望尽可能多地访问一个城市中的许多有趣的地点,而不需要更进一步。从他位于城市西北角的酒店出发,他打算到城市的东南角散步,然后再往后走。走到东南角时,他只会向东或向南走,当走回西北角时,他只会向北或向西走。在研究了城市地图之后,他意识到任务并非如此简单,因为某些区域被封锁了。所以他恳请你写一个程序来解决他的问题。
给定城市地图(2D网格),其中可步行区域用"。"标记,有趣的位置用" *"标记,被阻挡的区域用&标记。 #34;#",确定他可以访问的最大感兴趣的位置数。访问过两次的地点只计算一次。
*........
.....**#.
..**...#*
..####*#.
.*.#*.*#.
...#**...
*........
答案:7。
我最初的想法是分两部分来解决这个问题。
1)当游客从左上角开始。
2)当游客从右下角开始时。
对于答案,将它们添加到两个部分,就是这样。
这是第一部分的方法。
i and j were initially 0, 0.
path(int i, int j){
if(i == H && j == W){
return (strV[i][j] == '*')?1:0;
}
if(i >H || j >W || i<0 || j<0){
return 0;
}
if(visited[i][j] == 1){
//cout<<"vis";
return 0;
}
if(strV[i][j] == '#' ){
return 0;
}
visited[i][j] =1;
cout<<i<<" "<<j<<"\n";
// as i can go only down and right ,for the first part.
// south and east.
return max(path(i+1, j), path (i, j+1) ) + (strV[i][j] == '*')?1 :0;
}
同样地,我尝试计算第二部分。 由于我维护了访问过的阵列,因此不可能重新审视同一点。 希望这应该满足他们在问题中提到的条件。 我不确定这是否会解决问题,它会给出错误答案。
以下是问题链接:http://www.spoj.com/problems/TOURIST/
感谢您的时间。
答案 0 :(得分:2)
一些观察结果将帮助您更轻松地解决这个问题:
- 在回程中,游客只能在网格中向左或向上移动。这相当于在第一次旅行中向右或向下移动。所以 基本上这两次旅行没有区别。
- 由于两次旅行基本相同,我们只需要考虑第一次旅行。我们可以从(0,0)开始同时派2名游客 细胞。所以我们的状态将由(x1,y1,x2,y2)组成,其中(x1,y1)是 第一位游客的位置和(x2,y2)是第二位游客的位置 网格。
- 在每个步骤中,游客可以向右或向下移动,因此我们有4个移动选择(每个游客有2个选择)。
- 如果两个游客都在同一个小区(x1 == x2和y1 == y2),那么如果该小区是特殊的,我们只能添加1个结果。
- 该算法的时间复杂度为O(n ^ 4),可能无法及时运行。我们可以将复杂度降低到O(n ^ 3)。如果我们知道 第一位游客的位置是(x1,y1)第二位的x坐标 游客是x2然后我们必须有x1 + y1 = x2 + y2,因为它们都覆盖相同 相同时间的距离。所以y2 = x1 + y1-x2,我们的状态取决于 仅限于(x1,y1,x2)。
醇>
代码:
const int N 100+5
vector<string> board;
int dp[N][N][N]; // initialize with -1
int calc(int x1, int y1, int x2) {
int n=board.size(), m=board[0].size();
int y2=x1+y1-x2;
if(x1>=n || x2>=n || y1>=m || y2>=m) return 0; // out of range
if(board[x1][y1]=='#' || board[x2][y2]=='#') return 0; // path blocked so its an invalid move
if(dp[x1][y1][x2]!=-1) return dp[x1][y1][x2]; // avoid recalculation
int res=0;
if(board[x1][y1]=='*') res++;
if(board[x2][y2]=='*') res++;
if(board[x1][y1]=='*' && x1==x2 && y1==y2) res=1; // both tourist on same spot
int r=calc(x1+1, y1, x2); // first tourist down second tourist right
r=max(r, calc(x1+1, y1, x2+1)); // first tourist down second tourist down
r=max(r, calc(x1, y1+1, x2)); // first tourist right second tourist right
r=max(r, calc(x1, y1+1, x2+1)); // first tourist right second tourist down
res+=r;
dp[x1][y1][x2]=res; // memoize
return res;
}
答案 1 :(得分:1)
你的方法有一些缺陷。有些使得它提供了错误的解决方案,而有些只会导致搜索效率低下。
导致错误解决方案的缺陷是:
导致搜索效率低下的缺陷并不是在搜索最佳路径之前简化搜索域。通过在它们之间存在有效(非阻塞)路径时创建仅包含有趣位置作为节点和它们之间的连接的图形,可以显着减少搜索空间(取决于有趣位置的稀疏程度和块的丰富程度)
尽可能接近您的尝试我的建议是:
希望这是有帮助的
答案 2 :(得分:1)
这是JavaScript的解决方案。它递归尝试所有有效方向SE和NW,并保存其结果,如果它大于当前最大结果。
function solve(grid) {
var maxVisited = 0;
var rows = grid.length;
var cols = grid[0].length;
// used to make a new copy of the visited set
function copy(obj) {
return JSON.parse(JSON.stringify(obj));
}
// used to test a current location returning false or the grid value
function move(r, c) {
if(r < 0 || c < 0 || r >= rows || c >= cols) { return false; }
if(grid[r][c] === "#") { return false; }
return grid[r][c];
}
// recursively solve the problem
function solveRec(r, c, grid, goBack, visited) {
// end trip, check if visited is greater than current max
if(goBack === true && r === 0 && c === 0) {
var count = Object.keys(visited).length;
if(count > maxVisited) { maxVisited = count; }
return;
}
var m = move(r, c);
// invalid move
if(m === false) { return; }
// place of interest, add to visited set
if(m === "*") { visited["" + r + ":" + c] = true; }
// try a move, if at S.E. go back home (turn around)
if(goBack === true || (r === rows-1 && c === cols-1)) {
// north west
solveRec(r-1, c, grid, true, copy(visited));
solveRec(r, c-1, grid, true, copy(visited));
} else {
// south east
solveRec(r+1, c, grid, false, copy(visited));
solveRec(r, c+1, grid, false, copy(visited));
}
}
solveRec(0, 0, grid, false, {});
return maxVisited;
}
console.log(solve([
"*........".split(""),
".....**#.".split(""),
"..**...#*".split(""),
"..####*#.".split(""),
".*.#*.*#.".split(""),
"...#**...".split(""),
"*........".split("")
])); // 7
编辑以下是jsfiddle http://jsfiddle.net/reeyws86/您可能需要添加逻辑以避免角网情况,例如网格为空或只有1平方时。