0

假设我有一个函数 f:

f(0) = 0
f(i) = (i - 1) % 4

f(0..12):

0 0 1 2 3 0 1 2 3 0 1 2 3

我想找到循环开始和循环长度,分别为 1 和 4。龟兔算法适用于迭代函数,但我没有迭代函数。是否有其他算法适用于非迭代函数,或者可以为此修改龟兔算法吗?

编辑:

使用 Jason S 的回答,我设法想出了这个,这似乎是有效的:

public static Tuple<int, int> ModifiedTortoiseHare(Func<int, int> f, int x0 = 0, int checks = 4)
{
    for (; ; x0++)
    {
        int lam = 0, tortoise, hare;

        do
        {
            lam++;
            tortoise = f(x0 + lam);
            hare = f(x0 + 2 * lam);
        } while (tortoise != hare);

        int mu = -1;

        do
        {
            mu++;
            tortoise = f(x0 + mu);
            hare = f(x0 + mu + lam);
        } while (tortoise != hare);

        if (mu != 0) continue;

        bool correct = true;
        int lamCheckMax = lam * checks;

        for (int x = 0; x < lamCheckMax; x++)
        {
            if (f(x0 + x + mu) != f(x0 + x + mu + lam))
            {
                correct = false;
                if (mu != 0) x0 += mu - 1;
                break;
            }
        }

        if (correct) return Tuple.Create(x0 + mu, lam);
    }
}
4

2 回答 2

7

如果该函数是一个“黑匣子”,并且您有能力找到任何单个 x 的 f(x)(无论是对实数有效还是仅对整数有效),但您不知道其他任何内容,则没有通用方法找到一个循环开始和长度。例如,考虑函数

f(k) = (k - 1) % 4 + g(k)
g(k) = max(0, k-1000000)

那么 f(k) 看起来每 4 个整数重复一次,但是当你达到 k = 1000000 时,模式就会停止。


如果函数具有有限范围,并且您可以测试所有整数,则可以使用龟/兔算法(= Floyd 的循环查找算法提供帮助。

不是迭代函数评估,而是计算 f(k0 + k) 和 f(k0 + 2*k) 直到它们匹配,此时可疑周期为 k,您只需重复所有值以验证循环是否继续.

您的问题似乎与“我应该如何找到重复的单词序列?”等价的问题。其中有很多答案。

于 2011-06-18T16:43:36.933 回答
0

对于您给出的 fn,因为它除以 4,所以长度为 4,并且由于没有添加任何值,因此 0 实际上是循环的开始,而不是 1。如果您使用图形实现它,您实际上可以观察到这一点已被指出。由于这些是 fn 值,您可以改用链表,并且在 fn 返回的每个值上,如果它不存在,则将其添加到列表中,否则您可以有一个循环。假设只有 1 个循环。

于 2011-06-18T16:48:08.083 回答