Floyd 判圈算法

偶然间发现的这种神奇东西。。。

首先,他是干嘛的呢?

正如字面,他是在链表上判圈(环)的。

其次,为什么学他?

因为闲的

最后,他能有什么用途?

判圈!

是也不全是。

本蒟蒻的理解中,该算法是一个在有环链式结构里,可以跑的飞快并且无需记录访问的算法。

这意味着什么?可能有的题中我们的状态会重复经过,但是又不好储存,需要哈希之类的,但这时候他卡我们空间,我们记录不了,这时候能用到他。

该算法复杂度为 $O(n)$ ,有的时候由于更小的常数,加上更快的判断,还能起到优化时间的作用,是不是听起来很棒!

其实算法流程非常非常非常非常非常非常非常非常简单,就一句话:设两个变量 $a$,$b$,其中 $a$ 一次走一步,$b$一次走两步,直到二者相遇(小学数学)。

接下来甩上一道例题感受一下:传送门

是不是很哇塞,上来就能水蓝题。

这题大概就是说:你的计算器只会算平方,且每次算出来都只保留该数的最高位开始数 $n$ 位,你一直算数,求算出来的最大的数。

我们可以发现,只保留 $n$ 位,那就是说我们计算的数字只会是 $n$ 位数,所以显然会出现环(圈),这时候我们就按照他说的模拟,再加上判圈就好啦!

#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
int buf[10];
inline int nxt(int n,int k){
    if(!k)return 0;
    long long k2 = (long long)k * k;
    int l = 0;
    while(k2){buf[l++] = k2%10,k2/=10;}
    if(n > l)n = l;
    int ans = 0;
    for(int i=0;i<n;++i)
        ans = ans * 10 + buf[--l];
    return ans;    
}
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        int n,k;
        scanf("%d%d",&n,&k);
        int ans = k;
        int k1 = k,k2 = k;
        do{
            k1 = nxt(n,k1);//慢的一步一步走
            k2 = nxt(n,k2);ans = max(ans,k2);//快的一步走两步
            k2 = nxt(n,k2);ans = max(ans,k2);
        }while(k1 != k2);
        printf("%d\n",ans);
    }
}

 

posted @ 2022-04-19 09:52  Xu_brezza  阅读(148)  评论(1)    收藏  举报