zoj 1088题解--Josephus 问题,加速解决

<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">zoj 1088题目题目大意是,对n栋楼停电,先停第一栋,再隔m栋停一栋。数到最后一栋后从头循环计数,已经断电的不参与计数。要选取适当的m,使得即使其他楼都没电了,但第二栋楼仍然有电。 </span>

如果将该题视为普通的模拟算法,其时间复杂度将高达O(m*n)。由于题目给了很充足的时间和很小的m、n范围,一般的模拟算法即可完成。但有没有更高效的算法呢。

常见的优化方法是每断掉一栋楼的电,问题规模就减一,这样时间复杂度就降到了O(n)。 下面转帖内容:

问题描述:n个人(编号0~(n-1)),从0开始报数,报到(m-1)的退出,剩下的人继续从0开始报数。求胜利者的编号。

我们知道第一个人(编号一定是m%n-1) 出列之后,剩下的n-1个人组成了一个新的约瑟夫环(以编号为k=m%n的人开始):

k  k+1  k+2  ... n-2, n-1, 0, 1, 2, ... k-2

并且从k开始报0。

现在我们把他们的编号做一下转换:

k     --> 0

k+1   --> 1

k+2   --> 2

...

...

k-2   --> n-2

k-1   --> n-1

变换后就完完全全成为了(n-1)个人报数的子问题,假如我们知道这个子问题的解:例如x是最终的胜利者,那么根据上面这个表把这个x变回去不刚好就是n个人情况的解吗?!!变回去的公式很简单,相信大家都可以推出来:x‘=(x+k)%n

如何知道(n-1)个人报数的问题的解?对,只要知道(n-2)个人的解就行了。(n-2)个人的解呢?当然是先求(n-3)的情况 ---- 这显然就是一个倒推问题!好了,思路出来了,下面写递推公式:

令f[i]表示i个人玩游戏报m退出最后胜利者的编号,最后的结果自然是f[n]

递推公式

f[1]=0;

f[i]=(f[i-1]+m)%i;  (i>1)

一般使用这种方法的C/C++时间消耗在20ms以上,占用内存大概在272kB左右。

还可以使用j(2^n)=1的特性来优化计算,即对于原问题,对于n=2^p的情况,直接输出1而避免计算。   最后消耗时间0,空间168kb(c/c++消耗等同)。

下面贴出本人的原代码。这个算法已经非常接近最佳排行160KB。但是不知道如何继续降低空间消耗。 希望在学完COM一书后能有优化。

#include<cstdio>
using namespace std;
//Arthur::Xiaoqiang AN
int joseph(int k,int b)
{
	int res=0;
	for(int i=2;i<=k;++i)
		res=(res+b)%i;
	return res;
}

int main()
{
	int n,t;
	while(scanf("%d",&n),n)
	{
		t=n-1;
		if(t==2||t==4||t==8||t==16||t==32||t==64||t==128)
		{
			printf("2\n");
			continue;
		}
		else
		{
			for(int m=3;;++m)
				if(joseph(t,m)==0)
				{
					printf("%d\n",m);
					break;
				}
		}
	}
}

如果直接模拟,然后输出所有结果到数组,最后备查的话,也可以将时间降为0,但空间消耗可能会大于168KB。  本人用自己前面的代码,将结果输出到文本,并重新查表输出的代码如下:

(为vim打个广告, 将输出结果改造为数组值的过程全部使用vim实现,最多只需要十次以内的操作,一分钟就能搞定,强烈推荐使用vim编程)。

#include<stdio.h>
int main()
{
	int m[153];
	m[0]=-1;
	m[1]=-1;
	m[2]=-1;
    m[3]=2;
    m[4]=5;
    m[5]=2;
    m[6]=4;
    m[7]=3;
    m[8]=11;
    m[9]=2;
    m[10]=3;
    m[11]=8;
    m[12]=16;
    m[13]=4;
    m[14]=21;
    m[15]=6;
    m[16]=5;
    m[17]=2;
    m[18]=11;
    m[19]=20;
    m[20]=34;
    m[21]=8;
    m[22]=15;
    m[23]=10;
    m[24]=7;
    m[25]=13;
    m[26]=11;
    m[27]=13;
    m[28]=45;
    m[29]=18;
    m[30]=23;
    m[31]=8;
    m[32]=3;
    m[33]=2;
    m[34]=25;
    m[35]=75;
    m[36]=42;
    m[37]=13;
    m[38]=5;
    m[39]=23;
    m[40]=13;
 m[41]=50;
    m[42]=16;
    m[43]=18;
    m[44]=89;
    m[45]=38;
    m[46]=8;
    m[47]=39;
    m[48]=30;
    m[49]=29;
    m[50]=38;
    m[51]=7;
    m[52]=45;
    m[53]=23;
    m[54]=137;
    m[55]=46;
	m[56]=63;
    m[57]=17;
    m[58]=48;
    m[59]=5;
    m[60]=46;
    m[61]=34;
    m[62]=140;
    m[63]=33;
    m[64]=39;
    m[65]=2;
    m[66]=28;
    m[67]=29;
    m[68]=79;
    m[69]=33;
    m[70]=48;
    m[71]=3;
    m[72]=10;
    m[73]=46;
    m[74]=120;
    m[75]=6;
    m[76]=37;
    m[77]=17;
    m[78]=8;
    m[79]=44;
    m[80]=15;
    m[81]=160;
    m[82]=20;
    m[83]=35;
    m[84]=144;
    m[85]=104;
 m[86]=179;
    m[87]=153;
    m[88]=24;
    m[89]=8;
    m[90]=265;
    m[91]=19;
    m[92]=9;
    m[93]=62;
    m[94]=7;
    m[95]=139;
    m[96]=19;
    m[97]=44;
    m[98]=93;
    m[99]=182;
    m[100]=27;
    m[101]=158;
    m[102]=185;
    m[103]=193;
    m[104]=17;
    m[105]=82;
    m[106]=3;
    m[107]=11;
    m[108]=43;
    m[109]=55;
    m[110]=21;
    m[111]=41;
    m[112]=146;
    m[113]=29;
    m[114]=80;
    m[115]=59;
    m[116]=8;
    m[117]=29;
    m[118]=66;
    m[119]=19;
    m[120]=160;
    m[121]=59;
    m[122]=28;
    m[123]=129;
    m[124]=127;
    m[125]=120;
    m[126]=72;
    m[127]=45;
    m[128]=157;
    m[129]=2;
    m[130]=63;
    m[131]=127;
 m[132]=81;
    m[133]=318;
    m[134]=513;
    m[135]=98;
    m[136]=28;
    m[137]=32;
    m[138]=231;
    m[139]=236;
    m[140]=411;
    m[141]=26;
    m[142]=45;
    m[143]=5;
    m[144]=303;
    m[145]=228;
    m[146]=66;
    m[147]=9;
    m[148]=205;
    m[149]=65;
    m[150]=39;
    m[151]=16;

    int n;
    while(scanf("%d",&n),n)
    {
		printf("%d\n",m[n]);
    }
return 0;

}

				
时间: 2024-08-09 18:07:21

zoj 1088题解--Josephus 问题,加速解决的相关文章

ZOJ 1088

典型的Joseph问题……由于数据范围小,直接暴力就可以解决了…… 用到了链表的数据结构…… 时间:90毫秒. #include "stdio.h" #include "string.h" struct lianbiao{ int prev,next; }p[152]; const int INF=2147483647; void init(int n){ int i; for(i=2;i<n;i++){ p[i].prev=i-1; p[i].next=i+

2019山东省赛B - Flipping Game ZOJ - 4114 题解

题意: 初始有n个灯泡,灯泡状态是0和1,.现在有k轮操作,每次改变且仅改变m个的灯的状态,给定n盏灯的初始状态的最终状态,求有多少种解决改变灯的方案满足可以满足题目条件. 思路: 开始写的时候以为是组合计数和容斥原理什么鬼的,后来发现n,m,k的值都比较小,觉得应该是三维dp了,当然是瞎想,最后看题解还是一个二维dp可以解决的问题,只不过是三重循环.给队友lrr说了一下题解的状态定义,他也较快就写出来了.其实对于灯的状态,每次改变一次之后,现在的问题和之前的问题形式一样,只是k值和目标灯的状态

2019山东省赛K - Happy Equation ZOJ - 4123 题解

题意: 一个数论题,要求满足如下等式的x有多少个. 思路: 当时比赛是,队伍看到这个题,也没有做太多的思考,就是无从下手,几乎放弃.但是看到学校另外两支队伍都过了这个题,感觉自己还是好菜. 打表可以发现,当a为奇数的时候答案为1.当a为偶数的时候,x一定也是偶数,这个还是比较明显的. 对左边进行推导,因为a为偶数,设a=2*t,所以a^x=2^x*t^x,所以当x大于p时,这个求余之后一定为0.由于p很小,可以直接暴力求解,所以对于右边直接考虑x^a求余之后为0的x的情况.由于x为偶数.我们再次

UVA 12382 Grid of Lamps ZOJ 3732 Graph Reconstruction 可图判定性

Uva 12382 题目链接:点击打开链接 ZOJ 3732题解:点击打开链接 Uva12382 题意: 给定n*m的地板,每个地板上有一盏灯,要么亮要么暗. 下面n个数字表示每行至少亮的灯盏数 下面m个数字表示每列至少亮的灯盏数 求:开始灯都是暗的,最少点亮几盏灯能满足上述条件 思路: 先给行和列大到小排序,然后每次用行减掉列.减完后再排个序即可. 即:实时排序. #include <cstdio> #include <cstring> #include <iostream

移动端网页布局中需要注意事项以及解决方法总结

移动端网页布局中需要注意事项以及解决方法总结,这份对我们在布局移动端网页的时候非常有用! winphone系统a.input标签被点击时产生的半透明灰色背景怎么去掉<meta name="msapplication-tap-highlight" content="no">1.关闭iOS键盘首字母自动大写<input type="text" autocapitalize="off" />2.禁止文本缩放h

移动端布局注意事项及解决

1.winphone系统a.input标签被点击时产生的半透明灰色背景怎么去掉 <meta name="msapplication-tap-highlight" content="no"> 1.关闭iOS键盘首字母自动大写 <input type="text" autocapitalize="off" /> 2.禁止文本缩放 html {-webkit-text-size-adjust: 100%;}

永久免费云服务器搭建国内Moon服务加速ZeroTier

ZeroTier One本身的服务器都在国外访问速度很慢.可以通过搭建国内Moon服务加速解决连接慢的问题. 但是需要有固定外网IP的服务器,可以注册sanfengyun账号申请免费云服务器. 下面是配置Moon的步骤(Linux): 1.安装 moon,zerotier官方提供了比较方便的安装方式,一条命令即可完成: curl -s https://install.zerotier.com/ | sudo bash 2.生成moon配置文件 cd /var/lib/zerotier-onesu

移动前端知识的一些总结

<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Title</title></head><body>meta基础知识 H5页面窗口自动调整到设备宽度,并禁止用户缩放页面 ?html 代码<meta name="viewport" content="w

移动web资源整理

2013年初接触移动端,简单做下总结,首先了解下移动web带来的问题 设备更新换代快--低端机遗留下问题.高端机带来新挑战 浏览器厂商不统一--兼容问题多 网络更复杂--弱网络,页面打开慢 低端机性能差--页面操作卡顿 HTML5新技术多--学习成本不低 未知问题--坑多 面对这些问题,一开始我们只能在未知中试错,知道错误的方案才能更容易寻找正确的解决问题思路,2年多来,可看到移动web在业界不断趋向于成熟,各种框架和解决方案不断的涌现让移动端开发不再是个噩梦. 这几天把想到的一点经验先罗列出来