【图论】Floyd消圈算法
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消圈算法的更多相关文章
- 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 ...
- UVA 11549 CALCULATOR CONUNDRUM(Floyd判圈算法)
CALCULATOR CONUNDRUM Alice got a hold of an old calculator that can display n digits. She was bore ...
- UVA 11549 Calculator Conundrum (Floyd判圈算法)
题意:有个老式计算器,每次只能记住一个数字的前n位.现在输入一个整数k,然后反复平方,一直做下去,能得到的最大数是多少.例如,n=1,k=6,那么一次显示:6,3,9,1... 思路:这个题一定会出现 ...
- leetcode202(Floyd判圈算法(龟兔赛跑算法))
Write an algorithm to determine if a number is "happy". 写出一个算法确定一个数是不是快乐数. A happy number ...
- Floyd判圈算法
Floyd判圈算法 leetcode 上 编号为202 的happy number 问题,有点意思.happy number 的定义为: A happy number is a number defi ...
- Codeforces Gym 101252D&&floyd判圈算法学习笔记
一句话题意:x0=1,xi+1=(Axi+xi%B)%C,如果x序列中存在最早的两个相同的元素,输出第二次出现的位置,若在2e7内无解则输出-1. 题解:都不到100天就AFO了才来学这floyd判圈 ...
- Floyd判圈算法 UVA 11549 - Calculator Conundrum
题意:给定一个数k,每次计算k的平方,然后截取最高的n位,然后不断重复这两个步骤,问这样可以得到的最大的数是多少? Floyd判圈算法:这个算法用在循环问题中,例如这个题目中,在不断重复中,一定有一个 ...
- Floyd 判圈算法
Floyd 判圈算法 摘自维基百科, LeetCode 上 141题 Linked List Cycle 用到这个, 觉得很有意思. 记录一下. 链接: https://zh.wikipedia.or ...
- UVa 11549 计算器谜题(Floyd判圈算法)
https://vjudge.net/problem/UVA-11549 题意: 有一个老式计算器,只能显示n位数字,输入一个整数k,然后反复平方,如果溢出的话,计算器会显示结果的最高n位.如果一直这 ...
随机推荐
- .net 使用com组件操作word遇到的一些问题
1.警告: 方法“Microsoft.Office.Interop.Word._Document.Close(ref object, ref object, ref object)”和非方法“Micr ...
- Linux命令应用大词典-第28章 硬件管理
28.1 lscpu:显示有关CPU架构的信息 28.2 nproc:显示当前进程可用的CPU数目 28.3 chcpu:配置CPU
- Java应用基础微专业-设计篇
第1章--抽象与接口 1.1 抽象 An abstract class can be created without abstract methods, the purpose of doing th ...
- java核心技术 笔记
一 . 总览 1. 类加载机制:jdk内嵌的class_loader有哪些,类加载过程.--后面需要补充 2. 垃圾收集基本原理,常见的垃圾收集器,各自适用的场景.--后面需要补充 3. 运行时动态编 ...
- Centos7下安装mysql服务
yum install -y perl-Module-Install.noarch yum -y install perl perl-devel #命令下载mysql wget http://dev. ...
- 十:HDFS Short-Circuit Local Reads 短路本地读取
当client请求数据时,datanode会读取数据然后通过TCP协议发送给client.short-circuit绕过了datanode直接读取数据.short-circuit的前提是client和 ...
- POJ 3415 Common Substrings(后缀数组)
Description A substring of a string T is defined as: T(i, k)=TiTi+1...Ti+k-1, 1≤i≤i+k-1≤|T|. Given t ...
- Cow Contest(最短路floyed传递闭包)
Description N (1 ≤ N ≤ 100) cows, conveniently numbered 1..N, are participating in a programming con ...
- 软工2017第六周团队协作——个人PSP
10.20 --10.26本周例行报告 1.PSP(personal software process )个人软件过程. 类型 任务 开始时间 结束时间 中断时间 实际用 ...
- 软工1816 · Alpha冲刺(1/10)
团队信息 队名:爸爸饿了 组长博客:here 作业博客:here 组员情况 组员1(组长):王彬 过去两天完成了哪些任务 前后端代码规范统一 针对之前的alpha冲刺安排进一步细化任务卡片 明确apl ...