考虑:
a c p r c
x s o p c
v o v n i
w g f m n
q a t i t
如果i_index
位于j_index
旁边的任何一个位置,则字母i_index
与相邻到另一个字母j_index
:
* * *
* x *
* * *
此处所有*
都表示与x
相邻的位置。
任务是在磁贴中找到给定的字符串。条件是给定字符串的所有字符都应该是相邻的,并且可以不多次使用图块中的任何一个字符来构造给定的字符串。
我想出了一个简单的回溯解决方案,解决方案非常快,但最坏的情况时间真的更糟。
例如:假设磁贴有4x4填充所有 a ,因此16 a ,并且要查找的字符串是 aaaaaaaaaaaaaa < / em>,即15 a 和一个 b 。一个是消除字符串中没有出现的字符串。但是最糟糕的情况仍然会出现,说瓷砖有 abababababababab ,找到的字符串是 abababababababbb 。
我的尝试是这样的:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define MAX 5
int sp (char mat[MAX][MAX], char *pat, int c, int i, int j)
{
int r = 0;
char temp;
if (c == strlen (pat))
return 1;
if (((i<0) || (j<0)) || (i>=MAX) || (j>=MAX))
return 0;
if (mat[i][j] != pat[c])
return 0;
if (isupper (mat[i][j]))
return 0;
/* Save character and mark location to indicate
* DFS has visited this node, to stop other branches
* to enter here and cross over path
*/
temp = mat[i][j];
mat[i][j] = 0;
r |= sp (mat, pat, c+1, i-1, j-1);
r |= sp (mat, pat, c+1, i-1, j);
r |= sp (mat, pat, c+1, i-1, j+1);
r |= sp (mat, pat, c+1, i, j+1);
r |= sp (mat, pat, c+1, i+1, j+1);
r |= sp (mat, pat, c+1, i+1, j);
r |= sp (mat, pat, c+1, i+1, j-1);
r |= sp (mat, pat, c+1, i, j-1);
/* restore value */
mat[i][j] = temp;
/* mark if success */
if ((mat[i][j] == pat[c]) && (r == 1))
mat[i][j] = toupper (mat[i][j]);
return r;
}
/* Testing the `sp` module */
int main (void)
{
char mat[MAX][MAX] = {
{'a', 'c', 'p', 'r', 'c'},
{'x', 's', 'o', 'p', 'c'},
{'v', 'o', 'v', 'n', 'i'},
{'w', 'g', 'f', 'm', 'n'},
{'q', 'a', 't', 'i', 't'}
};
char pat[] = "microsoft";
int i, j;
for (i=0; i<5; i++)
{
for (j=0; j<5; j++)
printf ("%c ", mat[i][j]);
printf ("\n");
}
for (i=0; i<5; i++)
for (j=0; j<5; j++)
sp (mat, pat, 0, i, j);
printf ("\n\n\n");
for (i=0; i<5; i++)
{
for (j=0; j<5; j++)
{
if (isupper (mat[i][j]))
printf ("%c ", mat[i][j]);
else
printf (". ");
}
printf ("\n");
}
printf ("\n");
return 0;
}
打印:
a c p r c
x s o p c
v o v n i
w g f m n
q a t i t
. . . R .
. S O . C
. O . . I
. . F M .
. . T . .
函数sp
执行工作,执行反向跟踪。
有更好的方法吗?或者是否可以降低最坏情况下的时间?
答案 0 :(得分:4)
没有多项式算法,所以我认为你不会变得更好......
可以使用字母矩阵对任何网格图(具有度数&lt; = 4的节点的平面图)进行编码。以下网格
0-0-0
| | |
0 0-0
| |
0-0-0
可以通过将边缘转换为'a',顶点转换为'b'并将空格转换为'z'来进行转换
B a B a B
a z a z a
B z B a B
a z a z z
B a B a B
在原始图中寻找哈密尔顿路径相当于搜索字符串BaBaBaBaBaBaBaBaB(包含所有9个B)。但是NP-complete *中网格的哈密顿路径问题所以单词搜索问题是NP难的。
由于单词路径显然是多项式证书,矩阵上的单词搜索问题是NP完全。
*我记得前一段时间看到了这方面的证据并且Wikipedia确认了,但没有链接到参考&gt;:/
我很确定那里有更多这个问题。我刚从我的屁股中取出这个证据,我很确定不是第一个看到这个问题的人。至少有一个很好的机会,你可以在一个真正的杂志拼图中得到非退化的案例...
答案 1 :(得分:1)
一个简单的改进是在每次调用r
后检查sp
的值。如果r == 1
则停止调用sp
。你找到了解决方案。这是除非您需要找到所有可能的解决方案。
这样的事情(如果first为真,则逻辑OR运算符不计算第二个操作数):
r = sp (mat, pat, c+1, i-1, j-1)) ||
sp (mat, pat, c+1, i-1, j) ||
sp (mat, pat, c+1, i-1, j+1) ||
sp (mat, pat, c+1, i, j+1) ||
sp (mat, pat, c+1, i+1, j+1) ||
sp (mat, pat, c+1, i+1, j) ||
sp (mat, pat, c+1, i+1, j-1) ||
sp (mat, pat, c+1, i, j-1) ? 1 : 0;
答案 2 :(得分:0)
我认为你可能会发现,关注最坏的情况在这里会适得其反,因为没有真正的改进。但是,在“现实世界”案例中有许多有用的改进。例如,如果单词总是从字典中提取,如果它们的长度可能有限(或者在统计上具有长度的自然分布)。对于小网格,您可以想象提前搜索它们以查找字典中的所有单词,将列表存储在散列图中,然后执行简单查找,因为单词需要“测试”。所有的时间都用于构建索引,但如果网格很少更改,这可能是可以接受的。