最近 地铁 上玩这个
然后想了想 路径 算法
只会穷举~
思路: 1.格子p出发 找下一步 找到 重复1 失败 2
2,p下一步失败 重置p p的上一步 q 把p 加入q的失败记录 以q出发 重新1
第一版
function findWay(m, n,/*空点 不能走*/emptyArrs,/*起点*/start) {
let mn = new Array(m);
console.time('a1')
for (var i = 0; i < n; i++) {
mn[i] = []
for (var j = 0; j < m; j++) {
mn[i][j] = {
isEmpty: false,
isPassed: false,
lastStep: null,
nextStep: null,
failSteps: [],
x: i,
y: j,
toNext() {
let np = findNextStep([this.x, this.y])
if (np) {
return toNextStep([this.x, this.y], np)
}
else {
if (checkEnd()) {
return outPut();
}
else {
return this.toFail();
}
}
},
toFail() {
if (this.x == start[0] && this.y == start[1]) {
return console.error('没有路')
}
let last = this.lastStep;
if (!last) {
return console.error('有错误')
}
inTotalPoint--;
this.reset();
last.failSteps.push([this.x, this.y])
return last.toNext();
},
reset() {
this.isPassed = false;
this.failSteps = [];
this.lastStep = null;
this.nextStep = null;
}
}
}
}
let totalPoint = m * n;
let inTotalPoint = 1;
emptyArrs.forEach(item => {
mn[item[0]][item[1]].isEmpty = true;
totalPoint--;
})
function findNextStep(point) {
let p = mn[point[0]][point[1]];
if (!p || p.isEmpty) {
return false;
}
let ways = [-1, 0, 1]
let failSteps = p.failSteps;
for (var i = 0; i < 3; i++) {
for (var j = 0; j < 3; j++) {
let x = ways[i];
let y = ways[j];
if (x * x == y * y) {
continue;
}
let pto = [point[0] + ways[i], point[1] + ways[j]]
let np = getPoint(pto);
if (!np) {
continue;
}
if (np.isEmpty) {
continue;
}
if (np.isPassed) {
continue;
}
let isInFail = false;
for (var c in failSteps) {
if (failSteps[c][0] == pto[0] && failSteps[c][1] == pto[1]) {
isInFail = true;
break
}
}
if (isInFail) {
continue;
}
return pto;
}
}
return false;
}
function getPoint(p) {
return p && mn[p[0]] && mn[p[0]][p[1]]
}
let _count = 0
function toNextStep(point0, point1) {
let np0 = mn[point0[0]][point0[1]]
let np1 = mn[point1[0]][point1[1]]
np0.nextStep = np1;
np1.lastStep = np0;
np1.isPassed = true;
inTotalPoint++;
if (_count > 2200) {
requestAnimationFrame(() => {
np1.toNext();
})
_count = 0;
}
else {
_count++;
np1.toNext();
}
}
function checkEnd() {
return inTotalPoint == totalPoint
}
function outPut() {
let p = mn[start[0]][start[1]];
console.timeEnd('a1')
while (p) {
console.log(`i>${p.x},j${p.y}`)
p = p.nextStep;
}
}
mn[start[0]][start[1]].isPassed = true;
mn[start[0]][start[1]].toNext();
}
额 耗时 有点久 就上图 用了 40 多 分钟
第二版
优化: 把 周围的点缓存 减少循环次数
function findWay2(m, n,/*空点 不能走*/emptyArrs,/*起点*/start) {
let mn = new Array(m);
console.time('a2')
for (var i = 0; i < n; i++) {
mn[i] = []
for (var j = 0; j < m; j++) {
mn[i][j] = {
isEmpty: false,
isPassed: false,
lastStep: null,
nextStep: null,
arounds: [],
failSteps: [],
x: i,
y: j,
toNext() {
let np = findNextStep([this.x, this.y])
if (np) {
return toNextStep([this.x, this.y], np)
}
else {
if (checkEnd()) {
return outPut();
}
else {
return this.toFail();
}
}
},
toFail() {
if (this.x == start[0] && this.y == start[1]) {
return console.error('没有路')
}
let last = this.lastStep;
if (!last) {
return console.error('有错误')
}
inTotalPoint--;
this.reset();
last.failSteps.push([this.x, this.y])
return last.toNext();
},
reset() {
this.isPassed = false;
this.failSteps = [];
this.lastStep = null;
this.nextStep = null;
}
}
}
}
let totalPoint = m * n;
let inTotalPoint = 1;
emptyArrs.forEach(item => {
mn[item[0]][item[1]].isEmpty = true;
totalPoint--;
})
function findNextStep(point) {
let p = mn[point[0]][point[1]];
if (!p || p.isEmpty) {
return false;
}
let ways = [-1, 0, 1]
let failSteps = p.failSteps;
let arounds = p.arounds;
if (!arounds.length) {
for (var i = 0; i < 3; i++) {
for (var j = 0; j < 3; j++) {
let x = ways[i];
let y = ways[j];
if (x * x == y * y) {
continue;
}
let pto = [point[0] + ways[i], point[1] + ways[j]]
let np = getPoint(pto);
if (!np) {
continue;
}
if (np.isEmpty) {
continue;
}
arounds.push(pto)
}
}
}
for (var i in arounds) {
let pto = arounds[i];
let np = getPoint(pto);
if (np.isPassed) {
continue;
}
let isInFail = false;
for (var c in failSteps) {
if (failSteps[c][0] == pto[0] && failSteps[c][1] == pto[1]) {
isInFail = true;
break
}
}
if (isInFail) {
continue;
}
return pto;
}
return false;
}
function getPoint(p) {
return p && mn[p[0]] && mn[p[0]][p[1]]
}
let _count = 0
function toNextStep(point0, point1) {
let np0 = mn[point0[0]][point0[1]]
let np1 = mn[point1[0]][point1[1]]
np0.nextStep = np1;
np1.lastStep = np0;
np1.isPassed = true;
inTotalPoint++;
if (_count > 2000) {
requestAnimationFrame(() => {
return np1.toNext();
})
_count = 0;
}
else {
_count++;
return np1.toNext();
}
}
function checkEnd() {
return inTotalPoint == totalPoint
}
function outPut() {
let p = mn[start[0]][start[1]];
console.timeEnd('a2')
while (p) {
console.log(`i>${p.x},j${p.y}`)
p = p.nextStep;
}
}
mn[start[0]][start[1]].isPassed = true;
mn[start[0]][start[1]].toNext();
}
额 10分钟以内
第三版:
优化:
把附近的 和 找下一步 去掉循环 (只能上下左右)
直接带入点对象
function findWay3(m, n,/*空点 不能走*/emptyArrs,/*起点*/start) {
let mn = new Array(m);
console.time('a3')
for (var i = 0; i < n; i++) {
mn[i] = []
for (var j = 0; j < m; j++) {
mn[i][j] = {
isEmpty: false,
isPassed: false,
lastStep: null,
nextStep: null,
arounds: [],
failSteps: [],
x: i,
y: j,
toNext() {
let np = findNextStep(this)
if (np) {
return toNextStep(this, np)
}
else {
if (checkEnd()) {
return outPut();
}
else {
return this.toFail();
}
}
},
toFail() {
if (this.x == start[0] && this.y == start[1]) {
return console.error('没有路')
}
let last = this.lastStep;
if (!last) {
return console.error('有错误')
}
inTotalPoint--;
this.reset();
last.failSteps.push(this)
return last.toNext();
},
reset() {
this.isPassed = false;
this.failSteps = [];
this.lastStep = null;
this.nextStep = null;
}
}
}
}
let totalPoint = m * n;
let inTotalPoint = 1;
emptyArrs.forEach(item => {
mn[item[0]][item[1]].isEmpty = true;
totalPoint--;
})
function findNextStep(p) {
if (!p || p.isEmpty) {
return false;
}
let ways = [-1, 0, 1]
let failSteps = p.failSteps;
let arounds = getArounds(p)
return findStepIN(arounds, failSteps)
}
function getArounds(point) {
let arounds = point.arounds;
if (arounds.length) {
return arounds;
}
let p = getPoint([point.x - 1, point.y]);
if (p && !p.isEmpty) {
arounds.push(p);
}
p = getPoint([point.x + 1, point.y]);
if (p && !p.isEmpty) {
arounds.push(p);
}
p = getPoint([point.x, point.y - 1]);
if (p && !p.isEmpty) {
arounds.push(p);
}
p = getPoint([point.x, point.y + 1]);
if (p && !p.isEmpty) {
arounds.push(p);
}
return arounds;
}
function findStepIN(arounds, failSteps) {
let p0 = arounds[0];
if (p0 && !p0.isPassed && isNotInFail(p0, failSteps)) {
return p0;
}
p0 = arounds[1];
if (!p0) {
return null;
}
if (!p0.isPassed && isNotInFail(p0, failSteps)) {
return p0;
}
p0 = arounds[2];
if (!p0) {
return null;
}
if (!p0.isPassed && isNotInFail(p0, failSteps)) {
return p0;
}
p0 = arounds[3];
if (!p0) {
return null;
}
if (!p0.isPassed && isNotInFail(p0, failSteps)) {
return p0;
}
}
function isNotInFail(point, failSteps) {
if (point == failSteps[0]) {
return false;
}
if (failSteps[1] && point == failSteps[1]) {
return false;
}
if (failSteps[2] && point == failSteps[2]) {
return false;
}
if (failSteps[3] && point == failSteps[3]) {
return false;
}
return true;
}
function getPoint(p) {
return p && mn[p[0]] && mn[p[0]][p[1]]
}
let _count = 0
function toNextStep(np0, np1) {
np0.nextStep = np1;
np1.lastStep = np0;
np1.isPassed = true;
inTotalPoint++;
if (_count > 2500) {
requestAnimationFrame(() => {
return np1.toNext();
})
_count = 0;
}
else {
_count++;
return np1.toNext();
}
}
function checkEnd() {
return inTotalPoint == totalPoint
}
function outPut() {
let p = mn[start[0]][start[1]];
console.timeEnd('a3')
while (p) {
console.log(`i>${p.x},j${p.y}`)
p = p.nextStep;
}
}
mn[start[0]][start[1]].isPassed = true;
mn[start[0]][start[1]].toNext();
}
又少一些了 3 分钟左右
第四版:
把周围点 按 度数 排序
function findWay4(m, n,/*空点 不能走*/emptyArrs,/*起点*/start) {
let mn = new Array(m);
let memCount = 2500
console.time('a4')
for (var i = 0; i < n; i++) {
mn[i] = []
for (var j = 0; j < m; j++) {
mn[i][j] = {
isEmpty: false,
isPassed: false,
lastStep: null,
nextStep: null,
arounds: [],
failSteps: [],
x: i,
y: j,
toNext() {
let np = findNextStep(this)
if (np) {
return toNextStep(this, np)
}
else {
if (checkEnd()) {
return outPut();
}
else {
return this.toFail();
}
}
},
toFail() {
if (this.x == start[0] && this.y == start[1]) {
return console.error('没有路')
}
let last = this.lastStep;
if (!last) {
return console.error('有错误')
}
inTotalPoint--;
this.reset();
last.failSteps.push(this)
return last.toNext();
},
reset() {
this.isPassed = false;
this.failSteps = [];
this.lastStep = null;
this.nextStep = null;
}
}
}
}
let totalPoint = m * n;
let inTotalPoint = 1;
emptyArrs.forEach(item => {
mn[item[0]][item[1]].isEmpty = true;
totalPoint--;
})
initArounds(getPoint(start));
function findNextStep(p) {
if (!p || p.isEmpty) {
return false;
}
let ways = [-1, 0, 1]
let failSteps = p.failSteps;
let arounds = getArounds(p)
return findStepIN(arounds, failSteps)
}
function initArounds(point) {
if (point.arounds.length) {
return;
}
point.arounds = getArounds(point);
point.arounds.forEach(p => {
initArounds(p)
})
point.arounds.sort((a, b) => a.arounds.length > b.arounds.length)
}
function getArounds(point) {
// 结果 按度数排序
let arounds = point.arounds;
if (arounds.length) {
return arounds;
}
let p = getPoint([point.x - 1, point.y]);
if (p && !p.isEmpty) {
arounds.push(p);
}
p = getPoint([point.x + 1, point.y]);
if (p && !p.isEmpty) {
arounds.push(p);
}
p = getPoint([point.x, point.y - 1]);
if (p && !p.isEmpty) {
arounds.push(p);
}
p = getPoint([point.x, point.y + 1]);
if (p && !p.isEmpty) {
arounds.push(p);
}
return arounds;
}
function findStepIN(arounds, failSteps) {
let p0 = arounds[0];
if (p0 && !p0.isPassed && isNotInFail(p0, failSteps)) {
return p0;
}
p0 = arounds[1];
if (!p0) {
return null;
}
if (!p0.isPassed && isNotInFail(p0, failSteps)) {
return p0;
}
p0 = arounds[2];
if (!p0) {
return null;
}
if (!p0.isPassed && isNotInFail(p0, failSteps)) {
return p0;
}
p0 = arounds[3];
if (!p0) {
return null;
}
if (!p0.isPassed && isNotInFail(p0, failSteps)) {
return p0;
}
}
function isNotInFail(point, failSteps) {
if (point == failSteps[0]) {
return false;
}
if (failSteps[1] && point == failSteps[1]) {
return false;
}
if (failSteps[2] && point == failSteps[2]) {
return false;
}
if (failSteps[3] && point == failSteps[3]) {
return false;
}
return true;
}
function getPoint(p) {
return p && mn[p[0]] && mn[p[0]][p[1]]
}
let _count = 0
function toNextStep(np0, np1) {
np0.nextStep = np1;
np1.lastStep = np0;
np1.isPassed = true;
inTotalPoint++;
if (_count > memCount) {
requestAnimationFrame(() => {
return np1.toNext();
})
_count = 0;
}
else {
_count++;
np1.toNext();
}
}
function checkEnd() {
return inTotalPoint == totalPoint
}
function outPut() {
let p = mn[start[0]][start[1]];
console.timeEnd('a4')
while (p) {
console.log(`i>${p.x},j${p.y}`)
p = p.nextStep;
}
}
mn[start[0]][start[1]].isPassed = true;
mn[start[0]][start[1]].toNext();
}
30s 内
没有方向了
第五版:
优化:使用worker 第一步的 三个方向 开启3个worker
function findWay5(m, n,/*空点 不能走*/emptyArrs,/*起点*/start) {
console.time("a5")
//当起点的
startWorker([-1, 0])
startWorker([1, 0])
startWorker([0, 1])
startWorker([0, -1])
function startWorker(direction) {
var work = new Worker('./FindWayWorker.js')
var data = [m, n, emptyArrs, start, direction];
work.postMessage(JSON.stringify(data))
work.onmessage = e => {
console.timeEnd("a5")
console.log(e.data);
}
work.onerror = e => {
console.error(e.message)
}
}
}
20 秒 左右 没有 本质 提升
在减少 估计 只能 改算法了 无力了~~