编辑:允许对角线移动
我有一个5x5网格(只是为了让自己更容易,虽然会增长到30x30甚至更大)并且我试图确定2个网格之间的网格数,但是,它正在做我的头,我希望也许有人可以指出我正确的方向。我试图实现的基本上是用户选择2个网格,即3004
和3017
,然后它应该找到最短路径并计算网格。例如,3004
和3017
之间的网格数应为4
,3001
和3005
之间的网格数应为5
, 3001
和3017
之间的网格数应为4
,3001
和3002
之间的网格数应为2
等。
网格:
------------------------------------
| 3001 | 3002 | 3003 | 3004 | 3005 |
------------------------------------
| 3006 | 3007 | 3008 | 3009 | 3010 |
------------------------------------
| 3011 | 3012 | 3013 | 3014 | 3015 |
------------------------------------
| 3016 | 3017 | 3018 | 3019 | 3020 |
------------------------------------
| 3021 | 3022 | 3023 | 3024 | 3025 |
------------------------------------
我的数组按以下方式构建:
$grids = array(
1 => array(
1 => 3001,
2 => 3002,
3 => 3003,
4 => 3004,
5 => 3005
),
2 => array(
1 => 3006,
2 => 3007,
3 => 3008,
4 => 3009,
5 => 3010
),
3 => array(
1 => 3011,
2 => 3012,
3 => 3013,
4 => 3014,
5 => 3015
),
4 => array(
1 => 3016,
2 => 3017,
3 => 3018,
4 => 3019,
5 => 3020
),
5 => array(
1 => 3021,
2 => 3022,
3 => 3023,
4 => 3024,
5 => 3025
),
);
我尝试了什么:
我意识到我可以使用好的旧斜视 a 2 + b 2 = c 2
这对于一些例子来说非常有用,但不是每次都有。例如,如果我插入3004
和3017
,则网格计数应为4
,但是,它会吐出5
或者插入3001
并且3025
网格数将为7
,它位于网格本身之外。我明白为什么这些结果会出现,所以我想检查是否有办法改进公式以使其以某种方式工作?
这个问题让我很伤心,因为我非常接近我能尝到的解决方案。
非常感谢您提前获得所有帮助!
我目前的代码:(请原谅杂乱)
<style>
.grid {
display: inline-block;
line-height: 50px; padding-left: 10px; padding-right: 10px;
border:1px solid black;
}
.grid.active {
background: red;
}
</style>
<?php
/*
3001 3002 3003 3004 3005
3006 3007 3008 3009 3010
3011 3012 3013 3014 3015
3016 3017 3018 3019 3020
3021 3022 3023 3024 3025
*/
$from = 3001;
$to = 3025;
$grids = array(
1 => array(
1 => 3001,
2 => 3002,
3 => 3003,
4 => 3004,
5 => 3005
),
2 => array(
1 => 3006,
2 => 3007,
3 => 3008,
4 => 3009,
5 => 3010
),
3 => array(
1 => 3011,
2 => 3012,
3 => 3013,
4 => 3014,
5 => 3015
),
4 => array(
1 => 3016,
2 => 3017,
3 => 3018,
4 => 3019,
5 => 3020
),
5 => array(
1 => 3021,
2 => 3022,
3 => 3023,
4 => 3024,
5 => 3025
),
);
$from_cells = 1;
$from_rows = 1;
foreach ( $grids as $y => $xs )
{
$from_cells = 1;
foreach ( $xs as $x => $postcode )
{
if ( $postcode == $from )
{
break 2;
}
else
{
$from_cells++;
}
}
$from_rows++;
}
$to_cells = 1;
$to_rows = 1;
foreach ( $grids as $y => $xs )
{
$to_cells = 1;
foreach ( $xs as $x => $postcode )
{
if ( $postcode == $to )
{
break 2;
}
else
{
$to_cells++;
}
}
$to_rows++;
}
echo "From<hr/>X: $from_cells | Y: $from_rows<br/><hr/>To<hr/>X: $to_cells | Y: $to_rows";
$leg1 = 0;
$leg2 = 0;
$cell_short = ($from_cells < $to_cells) ? $from_cells : $to_cells;
$cell_long = ($from_cells > $to_cells) ? $from_cells : $to_cells;
for ( $i=$cell_short; $i <= $cell_long; $i++ )
{
$leg1 = $i;
}
$row_short = ($from_rows < $to_rows) ? $from_rows : $to_rows;
$row_long = ($from_rows > $to_rows) ? $from_rows : $to_rows;
for ( $i=$row_short; $i <= $row_long; $i++ )
{
$leg2 = $i;
}
echo "<hr/>Length: $leg1<br/>Height: $leg2";
$grid_count = pow($leg1,2) + pow($leg2,2);
$grid_count = floor(sqrt($grid_count));
echo "<hr/>Grids: $grid_count<hr/>";
foreach ( $grids as $y => $xs )
{
foreach ( $xs as $x => $postcode )
{
if ( $postcode == $from or $postcode == $to )
{
echo '<div class="grid active">'.$postcode.'</div>';
}
else
{
echo '<div class="grid">'.$postcode.'</div>';
}
}
echo '<br/>';
}
如果需要任何其他信息,请告诉我,我会把它丢进去。
答案 0 :(得分:2)
您可以进行的对角线移动次数限制为您必须遍历以到达目的地的行数或列数。所有其他移动可以是左/右或上/下,并保持最短距离。
那就是说,假设你知道你的细胞的行数和col数,我相信这会给你最短的距离:
$startCol = [column of starting cell];
$startRow = [row of starting cell];
$endCol = [column of end cell];
$endRow = [row of end cell];
$numMoves = 0;
$moveCol = 0;
$moveRow = 0;
/*
* figure out which direction the end cell is, in relation to the
* start cell.
*/
// end is to the right, so we need to add columns to the start
if( $startCol < $endCol ) {
$moveCol = 1;
}
// end is to the left (or in the same column), so we need to subtract
// column from the start
else {
$moveCol = -1;
}
// end is below the start, so we need to add rows
if( $startRow < $endRow ) {
$moveRow = 1;
}
// end is above (or in the same row), so we need to subtract rows to the start
else {
$moveRow = -1;
}
/*
* now go diagnoal until you hit either the row or the column
* that the end cell is in
*/
while( $startCol != $endCol && $startRow != $endRow ) {
$startCol += $moveCol;
$startRow += $moveRow;
$numMoves++;
}
/* at this point, we're either in the same row or the same column
* as our destination, so just move down that row or col until we
* reach the destination
*/
// already at the destination, don't do anything
if( $startCol == $endCol && $startRow == $endRow ) {
}
// in the same column, so move up/down rows
else if( $startCol == $endCol ) {
while( $startRow != $endRow ) {
$startRow += $moveRow;
$numMoves++;
}
}
// in the same row, so move left/right cols
else {
while( $startCol != $endCol ) {
$startCol += $moveCol;
$numMoves++;
}
}
echo "min moves: $numMoves";
在此示例中,您不需要任何网格知识,只要您假设开始和结束坐标实际上在网格内。
答案 1 :(得分:1)
也许不是最优雅的,也可以简化。但它的确有效:
假设:
$from = 3001;
$to = 3025;
$grids = array(
1 => array(
1 => 3001,
2 => 3002,
3 => 3003,
4 => 3004,
5 => 3005
),
2 => array(
1 => 3006,
2 => 3007,
3 => 3008,
4 => 3009,
5 => 3010
),
3 => array(
1 => 3011,
2 => 3012,
3 => 3013,
4 => 3014,
5 => 3015
),
4 => array(
1 => 3016,
2 => 3017,
3 => 3018,
4 => 3019,
5 => 3020
),
5 => array(
1 => 3021,
2 => 3022,
3 => 3023,
4 => 3024,
5 => 3025
),
);
算法:
// Determine the (x,y) coordinates of $from and $to
foreach($grids as $row=>$g) {
if (in_array($from, $g)) {
$from_row = $row;
foreach ($g as $col=>$val) {
if ($val==$from)
$from_col = $col;
}
}
if (in_array($to, $g)) {
$to_row = $row;
foreach ($g as $col=>$val) {
if ($val==$to)
$to_col = $col;
}
}
}
// Difference between $from cols, $to cols and $from rows, $to rows
$col_diff = abs($from_col-$to_col);
$row_diff = abs($from_row-$to_row);
if ($col_diff==4) {
$d = 5;
}
elseif ($col_diff==3) {
if ($row_diff==4)
$d = 5;
else
$d = 4;
}
elseif ($col_diff==2) {
if ($row_diff==4)
$d = 5;
elseif ($row_diff==3)
$d = 4;
else
$d = 3;
}
elseif ($col_diff==1) {
if ($row_diff==4)
$d = 5;
elseif ($row_diff==3)
$d = 4;
elseif ($row_diff==2)
$d = 3;
else
$d = 2;
}
elseif ($col_diff==0) {
if ($row_diff==4)
$d = 5;
elseif ($row_diff==3)
$d = 4;
elseif ($row_diff==2)
$d = 3;
elseif ($row_diff==1)
$d = 2;
else
$d = 1;
}
echo $from . ' -> ' . $to . ' = ' . $d;