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); } }

浙公网安备 33010602011771号