这是来自ACM ICPC Japan。链接here中解释了问题以及图表。
任何人都可以帮我解决逻辑吗?我只知道天真的蛮力方法并没有把我带到这里。
答案 0 :(得分:0)
蛮力确实似乎是解决方案:http://mainly-coding.blogspot.dk/2010/09/m-judge-10156-kaeru-jump.html。您只需要进一步优化您的解决方案。
你可以用动态编程来做n2 ^ n,但这会占用太多内存。
根据维基百科的说法,也有可能存在比这更快的算法,因为立方图上的hammilton路径可以解决为1.25 ^ n。
我认为这不是一个好问题,因为很明显蛮力比3 ^ 30更快,但很多人会尝试并取得成功。您可以证明,大多数时候您只有一个选项可以进行下一次跳跃,因此运行时间低于3 ^ n,但我不知道怎么做。
答案 1 :(得分:0)
以下是Javascript中的强力解决方案。您可以直接从代码段运行它。对于具有30个叶子的10x10样本网格,该算法将访问搜索树的11 683个节点。或者以不同的顺序查看可能的跳跃,我得到26 269次访问。就像@ThomasAhle预计的那样,这低于3 30 (205 891 132 094 649)。
进一步改进的一种方法是检测叶子变得无法到达,这可能导致更早的回溯。如果两个叶子成为单向行程,则相同:这无法解决,因此一旦检测到这种情况,算法就可以回溯。
我没有尝试任何这些优化,因为下面的实现在运行Firefox的极慢的笔记本电脑上只用0.1秒即可找到10x10样本的解决方案。
var directionLetters = 'URDL';
function parseInput(input) {
// Get input elements and return error message when not valid
var sp = input.trim().split(/\s+/g);
var h = parseInt(sp.shift());
var w = parseInt(sp.shift());
if (isNaN(w) || isNaN(h)) return "Invalid width or height";
var grid = sp.join('');
if (grid.length != w*h) return "Wrong amount of cells";
var badChars = grid.replace(/[\.oURDL]/g, '');
if (badChars.length) return "Bad cell characters ('" + badChars + "')";
// Turn grid into double linked list of leaves, in horizontal and vertical
// directions.
var count = 0;
var up = [];
for (var col = 0; col < w; col++) {
up[col] = null;
}
for (var line = 0; line < h; line++) {
var left = null;
for (var col = 0; col < w; col++) {
var ch = grid[line*w+col];
if (ch !== '.') {
leaf = {
row: line, // not really needed
col: col, // not really needed
neighbor: [
up[col],
null,
null,
left
]
};
if (left) {
left.neighbor[1] = leaf;
}
if (up[col]) {
up[col].neighbor[2] = leaf;
}
left = leaf;
up[col] = leaf;
if (directionLetters.indexOf(ch) !== -1) {
direction = directionLetters.indexOf(ch);
currentLeaf = leaf;
}
count++;
}
}
}
return {
count: count,
currentLeaf: currentLeaf,
direction: direction
};
}
function getValidJumps(leaves) {
var jumps = [];
for (var direction = 0; direction < 4; direction++) { // four directions
if ((direction ^ leaves.direction) !== 2 // cannot be opposite
&& leaves.currentLeaf.neighbor[direction]) {
// valid jump
jumps.push({
count: leaves.count - 1,
currentLeaf: leaves.currentLeaf.neighbor[direction],
direction: direction
});
}
}
return jumps;
}
function removeLeaf(leaf) {
// adapt double linked lists to exclude this leaf
for (var i = 0; i < 4; i++) {
if (leaf.neighbor[i]) {
leaf.neighbor[i].neighbor[i ^ 2] = leaf.neighbor[i ^ 2];
}
}
}
function restoreLeaf(leaf) {
// adapt double linked lists to include this leaf
for (var i = 0; i < 4; i++) {
if (leaf.neighbor[i]) {
leaf.neighbor[i].neighbor[i ^ 2] = leaf;
}
}
}
// Main recursive algorithm:
function searchPath(leaves) {
if (leaves.count <= 1) return ''; // found a solution
var jumps = getValidJumps(leaves);
removeLeaf(leaves.currentLeaf);
for (var j = 0; j < jumps.length; j++) {
var path = searchPath(jumps[j]);
if (path !== false) return directionLetters[jumps[j].direction] + path;
};
restoreLeaf(leaves.currentLeaf);
return false; // no solution
}
// I/O
document.getElementById('solve').onclick = function() {
var leaves = parseInput(document.getElementById('input').value);
document.getElementById('output').textContent =
typeof leaves == "string" // error in input?
? leaves : searchPath(leaves);
}
document.getElementById('input').oninput = function() {
document.getElementById('output').textContent = ''; // clear
}
&#13;
<textarea id="input" rows=11 cols=20 style="float:left">
10 10
.o....o...
o.oo......
..oo..oo..
..o.......
..oo..oo..
..o...o.o.
o..U.o....
oo......oo
oo........
oo..oo....
</textarea>
<button id="solve">Solve</button>
<h4>Solution:</h4>
<div id="output"></div>
&#13;