简单介绍一下背景,,这是赛尔号手游的一个游戏任务,叫做青龙祭坛,是获取青龙这个精灵的前置条件。下面是这个任务的截图

规则
要求是将所有的灯点亮,我对规则做了抽象,然后把这部分简单说明一下
有1,2,3,4,5,6,7个据点。 可以选择一个熄灭的据点点亮,点亮的规则如下。
- 选择点亮的 据点后,可以点亮该据点和改据点对面的两个据点。 如果对面的两个据点有点亮状态的那么会将其熄灭,如果本身熄灭的会亮起
- 据点的对应规则如下
- 点亮 1 据点 对应 的点是 4 ,5 据点,
- 点亮 2 据点对应的是 5, 6 据点。
- 点亮 3 据点对应的是 6,7据点。 依次类推。 最后点亮7据点对应的是 的据点是3,4。
目前节点的状态是2,6 熄灭(数据格式 array<boolean>
的数组) 请问 接下来这么做使得据点全部被点亮,要求 输出是 array<number>
的数组, 含义是第 i + 1 步时应该进行操作的据点
input example:
arduino
[true, false, true, true, true, false, true];
output example
csharp
[2, 5, 1, 2, 4, 7, 3, 4]
如果有一点刷算法题的经验,那么答案其实已经呼之欲出了
那么大家是怎么做的呢
大多数人的做法是通过手动验证,又或者直接找一个前人验证后的路线走一遍
下面 截取b站这个任务的攻略,可以看出其实用的大多都是一种刀耕火种的求解方式

另一个up 攻略的评论区

解法示例
一个简单的bfs标记 visited,模版直接秒了
javascript
// 定义每个据点对应的对面据点
const OPPOSITE_POINTS = {
1: [4, 5],
2: [5, 6],
3: [6, 7],
4: [7, 1],
5: [1, 2],
6: [2, 3],
7: [3, 4]
};
/**
* 将据点状态转换为数字表示
* @param {Array} state - 据点状态数组,true表示点亮,false表示熄灭
* @returns {number} - 状态对应的数字
*/
function stateToNumber(state) {
return parseInt(state.map(s => s ? '1' : '0').join(''), 2);
}
/**
* 将数字转换为据点状态
* @param {number} num - 状态数字
* @returns {Array} - 据点状态数组
*/
function numberToState(num) {
const binary = num.toString(2).padStart(7, '0');
return binary.split('').map(bit => bit === '1');
}
/**
* 执行一次点亮操作
* @param {Array} currentState - 当前状态
* @param {number} point - 要操作的据点编号(1-7)
* @returns {Array} - 操作后的新状态
*/
function togglePoint(currentState, point) {
const newState = [...currentState];
const pointIndex = point - 1; // 转换为数组索引
// 切换当前据点状态
newState[pointIndex] = !newState[pointIndex];
// 切换对面两个据点状态
const oppositePoints = OPPOSITE_POINTS[point];
for (const oppositePoint of oppositePoints) {
const oppositeIndex = oppositePoint - 1;
newState[oppositeIndex] = !newState[oppositeIndex];
}
return newState;
}
/**
* 检查状态是否全部点亮
* @param {Array} state - 据点状态
* @returns {boolean} - 是否全部点亮
*/
function isAllLighted(state) {
return state.every(point => point);
}
/**
* 获取所有可能的下一步操作
* @param {Array} state - 当前状态
* @returns {Array} - 可操作的据点列表
*/
function getAvailableMoves(state) {
const moves = [];
for (let i = 0; i < state.length; i++) {
if (!state[i]) { // 只选择熄灭的据点
moves.push(i + 1);
}
}
return moves;
}
/**
* 使用BFS寻找最短解决方案
* @param {Array} initialState - 初始状态
* @returns {Array|null} - 解决方案路径,如果没有解则返回null
*/
function solveLightingPuzzle(initialState) {
const queue = [{ state: initialState, path: [] }];
const visited = new Set();
while (queue.length > 0) {
const { state, path } = queue.shift();
const stateNum = stateToNumber(state);
if (visited.has(stateNum)) {
continue;
}
visited.add(stateNum);
// 检查是否达到目标状态
if (isAllLighted(state)) {
return path;
}
// 获取所有可能的下一步操作
const availableMoves = getAvailableMoves(state);
for (const move of availableMoves) {
const newState = togglePoint(state, move);
const newPath = [...path, move];
queue.push({ state: newState, path: newPath });
}
}
return null; // 没有找到解决方案
}
/**
* input: Array<boolean>
* output: Array<number>
*/
/**
* 主函数
*/
function main() {
// 初始状态:2和6号据点熄灭,其他点亮
const initialState = [true, false, true, true, true, false, true];
const solution = solveLightingPuzzle(initialState);
console.log(solution);
return solution;
}
// 运行程序
main();
最后用cursor顺手补了一个界面