解决Kaeru Jump(ACM ICPC日本)

时间:2016-01-23 07:55:38

标签: algorithm greedy

这是来自ACM ICPC Japan。链接here中解释了问题以及图表。

任何人都可以帮我解决逻辑吗?我只知道天真的蛮力方法并没有把我带到这里。

2 个答案:

答案 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;
&#13;
&#13;