毫无卵用的百度百科

Definition&Solution

  对于一个给定的链表,如何判定它是否存在环以及环的长度问题,可以使用Floyd消圈算法求出。

  从某种意义上来讲,带环的链表在本质上是一个有向图

  考虑下面的事实:假定小Y和小Z在圆形操场上跑步,小Z的速度是小Y的两倍,那么总存在一个时刻,使得小Z和小Y在同一个位置但是小Z比小Y多跑了若干圈。

  该算法的复杂度为O(n)。

  代码如下:

void floyd_c() {
int c1=list_begin,c2=list_begin;//c=child
do {
c1=nxt[c1];
c2=nxt[c2]; dosth();
c2=nxt[c2]; dosth();
} while(c1!=c2);
return;
}

  其中dosth应具体情况具体分析。

  考虑如何求出该环的起点。

  如果你不理解环为什么有起点,不妨观察下面的链表:

  由于1是链表的起点,以1号点为起点遍历整张链表,是从3号点进入原谅环的,我们认为3号点是原谅环的起点。

  如何求出起点。

  将小Z和小Y都放到链表的起点上,当两者相遇时,将其中一个指针再次放到起点上,二者再次相遇的位置就是环的起点。

  证明如下:

    由于含有多个环的链表可以通过数学归纳由含有一个环的链表证明,故不妨设所研究的链表只有一个环,同时还有一条长度至少为1(一个点)的链。

    设环的长度为n,链的长度为m。快慢指针第一次相遇在环上的第k个点,那么有:

    快指针的路程Sa=m+A*n+k,其中A∈Z,代表走了几圈①

    慢指针的路程Sb=m+B*n+k。其中B∈Z,代表走了几圈②

    由于快指针的速度是慢指针的两倍,即:

    Va=2Vb③

    在运动时间一定的情况下有:

    Sa=2Sb④

    ①-②得:

    Sa-Sb=(A-B)*n⑤

    联立④⑤解得Sb=(A-B)*n⑥

    由于A,B∈Z,且显然A>B,所以Sa,Sb都是圈长度的倍数。

    不妨设Sb=T*n。显然从起点出发,走过T*n+m时,到达环的起点。

    那么在两个指针相遇时,我们让两个指针的速度都为1,走m个单位就可以到达环的起点,这时快指针的路程为2Sb+m。慢指针的路程为Sb+m。

    由于Sb=T*n,这时的路程可以理解为快指针走到m处然后绕了几圈,绕圈路程为2Sb,慢指针从路程为Sb的位置走了m,那么二者的相遇的地方显然是环的起点。

    特别的,因为vb=1。所以Sb即为循环的次数。通过⑥式已经证明,该算法的复杂度为O(n)。其中常数随环的形态而改变。

 

Sample

UVA11549 Calculator Conundrum

Description

有一个非常无聊的傻逼,有一天他闲的没事干玩一个老式计算器,这个计算器只能显示答案最高的n位。比如n=2,计算99+1的答案为100时,显示为10。

现在他一开始输入了一个数字k,保证在能显示的范围内,然后将k平方,然后将答案平方,再平方……

这个无聊的人想知道屏幕上显示的最大数时多少。

Input

第一行是数据组数,对于每组数据,包含:

  • 一个整数n,一个整数k

Output

对于每组数据,输出:

  • 对应答案

Sample Input


Sample Output


Hint

n≤9

Solution

简单的数学归纳可以证明计算器上的数字是会出现循环的,可以使用Floyd消圈算法解决此题。

Code

#include<cstdio>
#define rg register
#define ci const int
#define ll long long int inline void qr(int &x) {
char ch=getchar(),lst=NULL;
while(ch>''||ch<'') lst=ch,ch=getchar();
while(ch>=''&&ch<='') x=(x<<)+(x<<)+(ch^),ch=getchar();
if (lst=='-') x=-x;
} char buf[];
inline void write(int x,const char aft,const bool pt) {
if(x<) {putchar('-');x=-x;}
int top=;
do {
buf[++top]=x%+'';
x/=;
} while(x);
while(top) putchar(buf[top--]);
if(pt) putchar(aft);
} template <typename T>
inline T mmax(const T &a,const T &b) {if(a>b) return a;return b;}
template <typename T>
inline T mmin(const T &a,const T &b) {if(a<b) return a;return b;}
template <typename T>
inline T mabs(const T &a) {if(a<) return -a;return a;} template <typename T>
inline void mswap(T &a,T &b) {T temp=a;a=b;b=temp;} int t,n,k,ans; int nxt(ci); int main() {
qr(t);
while(t--) {
n=k=;qr(n);qr(k);
int c1=k,c2=k;ans=k;
do {
c1=nxt(c1);
c2=nxt(c2);ans=mmax(ans,c2);c2=nxt(c2);ans=mmax(ans,c2);
} while(c1!=c2);
write(ans,'\n',true);
}
return ;
} short bufff[];
int nxt(int x)
{
if(!x)return ;
long long kf=(long long)x*x;
int L=;
while(kf>) bufff[L++]=kf%,kf/=;
int temp=n;
if(temp>L) temp=L;
int sum=;
for(int i=;i<temp;++i) sum=(sum<<)+(sum<<)+bufff[--L];
return sum;
}

Summary

  1、Floyd消圈算法是达到理论下限的判断有向图上环的算法。尽管它的常数难以控制,但是十分的实用并且好写。

  2、在证明的最后使用了等效替代法,在其他的OI毒瘤题中,也应注意该方法的应用。

【图论】Floyd消圈算法的更多相关文章

  1. SGU 455 Sequence analysis(Cycle detection,floyd判圈算法)

    题目链接:http://acm.sgu.ru/problem.php?contest=0&problem=455 Due to the slow 'mod' and 'div' operati ...

  2. UVA 11549 CALCULATOR CONUNDRUM(Floyd判圈算法)

    CALCULATOR CONUNDRUM   Alice got a hold of an old calculator that can display n digits. She was bore ...

  3. UVA 11549 Calculator Conundrum (Floyd判圈算法)

    题意:有个老式计算器,每次只能记住一个数字的前n位.现在输入一个整数k,然后反复平方,一直做下去,能得到的最大数是多少.例如,n=1,k=6,那么一次显示:6,3,9,1... 思路:这个题一定会出现 ...

  4. leetcode202(Floyd判圈算法(龟兔赛跑算法))

    Write an algorithm to determine if a number is "happy". 写出一个算法确定一个数是不是快乐数. A happy number ...

  5. Floyd判圈算法

    Floyd判圈算法 leetcode 上 编号为202 的happy number 问题,有点意思.happy number 的定义为: A happy number is a number defi ...

  6. Codeforces Gym 101252D&&floyd判圈算法学习笔记

    一句话题意:x0=1,xi+1=(Axi+xi%B)%C,如果x序列中存在最早的两个相同的元素,输出第二次出现的位置,若在2e7内无解则输出-1. 题解:都不到100天就AFO了才来学这floyd判圈 ...

  7. Floyd判圈算法 UVA 11549 - Calculator Conundrum

    题意:给定一个数k,每次计算k的平方,然后截取最高的n位,然后不断重复这两个步骤,问这样可以得到的最大的数是多少? Floyd判圈算法:这个算法用在循环问题中,例如这个题目中,在不断重复中,一定有一个 ...

  8. Floyd 判圈算法

    Floyd 判圈算法 摘自维基百科, LeetCode 上 141题 Linked List Cycle 用到这个, 觉得很有意思. 记录一下. 链接: https://zh.wikipedia.or ...

  9. UVa 11549 计算器谜题(Floyd判圈算法)

    https://vjudge.net/problem/UVA-11549 题意: 有一个老式计算器,只能显示n位数字,输入一个整数k,然后反复平方,如果溢出的话,计算器会显示结果的最高n位.如果一直这 ...

随机推荐

  1. requests,lxml爬启信宝

    首先, 添加requests模块: 然后, 添加lxml模块: 启信宝登录抓包: QiXinBao.py: import requestsfrom lxml import etree loginUrl ...

  2. Kotlin对象:仅一行代码就可创建安全的单例

    作者:Antonio Leiva 时间:Jun 20, 2017 原文链接:https://antonioleiva.com/objects-kotlin/ Kotlin对象是Android开发人员不 ...

  3. Java开发工程师(Web方向) - 04.Spring框架 - 第5章.Web框架

    第5章--Web框架 Web框架概述 Web框架单元测验 本次得分为:13.50/15.00, 本次测试的提交时间为:2017-09-25 1单选(2分) 关于Spring MVC中Dispatche ...

  4. 转:vue生命周期流程图

  5. [转载]Tensorflow中reduction_indices 的用法

    Tensorflow中reduction_indices 的用法 默认时None 压缩成一维

  6. PokeCats开发者日志(十二)

      现在是PokeCats游戏开发的第六十一天的晚上,终于拿到软著权登记证书了!   看来易版权确实是个值得信赖的代办机构呢,400块花的不冤.

  7. Stax解析XML示例代码

    package org.itat.stax; import java.io.IOException; import java.io.InputStream; import javax.xml.pars ...

  8. 调用init方法 两种方式 一个是浏览器方法 一个是 xml中手工配置(load-on-startup)

    调用init方法 两种方式 一个是浏览器方法 一个是 xml中手工配置(load-on-startup)

  9. 当重写了 httpservlet重写了GenericServlet的init方法时候 必须显示调用GenericServlet的init方法时候 才能在别的方法(父类创建config实例) 例如 doget里面使用servletContext对象 不重写init 则可以直接使用

  10. 【bzoj1507】[NOI2003]Editor /【bzoj1269】[AHOI2006]文本编辑器editor Splay

    [bzoj1507][NOI2003]Editor 题目描述 输入 输入文件editor.in的第一行是指令条数t,以下是需要执行的t个操作.其中: 为了使输入文件便于阅读,Insert操作的字符串中 ...