4x3锁定图案

4

我发现了这个问题

它要求计算在4x3的网格中制作特定长度锁定图案的方法数,并遵循规则。 有些点可能不能包含在路径中

有效的模式具有以下属性:

  • 一个图案可以用它第一次接触的点的序列来表示(按照绘制图案的顺序),从(1,1)到(2,2)的图案与从(2,2)到(1,1)的图案不同。

  • 对于图案表示中的每两个相邻点A和B,如果连接A和B的线段通过其他点,则这些点也必须在序列中,并且出现在A和B之前,否则该图案将无效。例如,以(3,1)开始然后是(1,3)的图案表示是无效的,因为线段通过(2,2),而在(3,1)之前未在图案表示中出现,此图案的正确表示应为(3,1)(2,2)(1,3)。但是(2,2)(3,2)(3,1)(1,3)的图案是有效的,因为(2,2)出现在(3,1)之前。

  • 在图案表示中,即使图案通过另一个有效线段再次接触同一点,我们也不会多次提及该点,并且图案中的每个线段都必须从图案之前未接触过的一个点到达另一个点,并且它可能穿过已经出现在图案中的一些点。

  • 图案的长度是图案表示中每两个相邻点之间的曼哈顿距离之和。两点(X1,Y1)和(X2,Y2)之间的曼哈顿距离是| X1-X2 | + | Y1-Y2 |(其中| X |表示X的绝对值)。

  • 一个图案必须至少接触两个点

我的方法是一种暴力算法,循环遍历点,从该点开始使用递归减少长度,直到达到零长度,然后将组合数加1。有没有一种数学方程来计算它或者有更好的算法?
更新:这是我所做的,它给出了一些错误的答案!我认为问题在于 isOk 函数!notAllowed 是不允许点的全局位掩码。
bool isOk(int i, int j, int di,int dj, ll visited){
    int mini = (i<di)?i:di;
    int minj = (j<dj)?j:dj;

    if(abs(i-di) == 2 && abs(j-dj) == 2 && !getbit(visited, mini+1, minj+1) )
        return false;
    if(di == i && abs(j - dj) == 2 && !getbit(visited, i,minj+1) )
        return false;
    if(di == i && abs(j-dj) == 3 && (!getbit(visited, i,1) || !getbit(visited, i,2)) )
        return false;
    if(dj == j && abs(i - di) == 2 && !getbit(visited, 1,j) )
        return false;

    return true;
}

int f(int i, int j, ll visited, int l){
    if(l > L) return 0;
    short& res = dp[i][j][visited][l];
    if(res != -1) return res;
    res = 0;
    if(l == L) return ++res;

    for(int di=0 ; di<gN ; ++di){
        for(int dj=0 ; dj<gM ; ++dj){
            if( getbit(notAllowed, di, dj) || getbit(visited, di, dj) || !isOk(i,j, di,dj,  visited) )
                continue;
            res += f(di, dj, setbit(visited, di, dj), l+dist(i,j , di,dj));
        }
    }
    return res;
}
2个回答

3

我的回答对这个问题同样适用。

f(i,j,visited,k)表示完成部分图案的方法数,当我们当前在节点(i,j),已经访问了集合visited中的顶点,并且到目前为止走过了路径长度k。我们可以将visited表示为位掩码。

我们可以通过尝试所有可能的下一步移动并应用DP来重用子问题的解来递归计算f(i,j,visited,k)

f(i,j, visited, L) = 1

f(i,j, visited, k) = 0 如果 k > L

f(i,j, visited, k) = sum(possible moves (i', j'): f(i', j', visited UNION {(i',j')}, k + dis((i,j), (i',j')))

可能的移动是那些穿过若干个访问过的顶点并以一个未访问(且非禁止)的顶点结束的移动。

如果D是禁止顶点的集合,则问题的答案为
sum((i,j) not in D: f(i,j, {(i,j)}, L))。
运行时间大约为O(X^2 * Y^2 * 2^(X*Y) * 最大可能长度)。我猜最大可能长度实际上远远低于1000
更新:我实现了这个解决方案并且它被接受了。我按以下方式列举可能的移动:假设我们在点(i,j),已经访问了顶点集合visited。枚举所有不同的互质对(dx,dy) 0 <= dx < X且0 <= dy < Y。然后找到最小的k,使得P_k = (i + kdx, j + kdy)仍然是一个有效的网格点,并且P_k不在visited中。如果P_k没有被禁止,那么它是一个有效的移动。
最大可能路径长度为39。
我正在使用一个DP数组,大小为3 * 4 * 2^12 * 40,用于存储子问题结果。

你能否更详细地解释一下算法,或者提供伪代码? - Rami Jarrar
Niklas B,我还在学习DP,我尝试适应这个问题的算法,但我做不到,你能帮帮我吗? - Rami Jarrar
@RamiJarrar 我可以回答问题并澄清我的答案。所以请提出问题(但请不要要求代码)。先从一些比较简单的位掩码DP任务开始做起,这样会更有帮助。 - Niklas B.
好的,你能解释一下 f(i,j,visited, L) 的算法吗? - Rami Jarrar
@RamiJarrar 我添加了明确的递归。你能否具体说明一下你不理解“在我们当前处于节点(i,j)且不能再访问集合visited中的顶点时,用大小为L的后缀完成部分模式的方法数”这个定义的哪些内容? - Niklas B.
显示剩余3条评论

0

有几个组合的属性可以用来优化暴力方法:

  1. 使用镜像图像(水平、垂直或两者)可以为每个找到的组合生成4个组合(除了水平或垂直线)。也许您可以考虑只从一个象限开始的组合。

  2. 通常可以通过平移(移动组合)生成相同长度的其他组合。


好的,但是可能有一些点没有包含在路径中,这会破坏镜像吗?你能再解释一下吗! - Rami Jarrar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接