先看视频更好理解,约瑟夫问题模拟算法可视化程序_C++精灵库算法可视化程序(抖音C++精灵库官方账号):
https://www.douyin.com/video/7602999293472984355
场景设定:在肖申克监狱的院子里,一群囚犯围成一个圈,正在进行一个奇特的"游戏"。安迪(Andy)和瑞德(Red)站在一旁,观察着这一切。
瑞德(Red):嘿,安迪,你看那边那群家伙在搞什么名堂啊?
安迪(Andy):哦,瑞德,这是他们在玩"约瑟夫游戏"。每次报数到3的人就得"出局",就像是一种残酷的淘汰赛。
瑞德(Red):听起来挺有意思的。那他们是怎么开始的?
安迪(Andy):你看,他们从0号开始,每个人按顺序报数。1,2,3------报到3的那位兄弟就得"阵亡"了。
瑞德(Red):(笑)"阵亡"?这词用得真贴切。那第一个"阵亡"的是谁?
安迪(Andy):(指着屏幕)看,是2号。他刚报完"3",就"阵亡"了。现在轮到5号接着报数。
瑞德(Red):(点头)嗯,5号接着报"1",然后8号报"2",1号报"3"------他又"阵亡"了。
安迪(Andy):没错,就这样一轮一轮地淘汰。每次"阵亡"的人都会变成半透明,就像魂魄出窍一样。
瑞德(Red):(大笑)魂魄出窍!这话说得我都有点毛骨悚然了。那现在轮到谁了?
安迪(Andy):现在是6号报"3",他也"阵亡"了。游戏继续,直到所有人都"阵亡"。
瑞德(Red):(惊叹)哇,这游戏真是既刺激又残酷。那最后的"阵亡"顺序是怎样的?
安迪(Andy):(指着屏幕上的序列)你看,最终的"阵亡"顺序是:2、5、8、1、6、0、7、4、9、3。每个人按照这个顺序一一"阵亡"。
瑞德(Red):(感叹)真是精妙的设计。这游戏不仅考验智力,还考验心理承受能力。
安迪(Andy):(微笑)是啊,瑞德。在这肖申克的院子里,我们总能找到各种方式来打发时间,甚至在"阵亡"中找到乐趣。
瑞德(Red):(大笑)安迪,你总是能用最乐观的心态来看待一切。来,我们再去看看他们怎么玩下一个轮次吧!
旁白:在肖申克的高墙之内,这群囚犯用"约瑟夫游戏"找到了一丝丝生活的乐趣。而安迪和瑞德,也在这游戏中,找到了彼此间的默契与友谊。这就是肖申克的故事,一个关于希望与自由的故事。
程序所有代码如下:
// 约瑟夫问题模拟算法可视化程序,本程序需C++精灵库V1.0.3。
// 下面拟有10个人,报到3的出队,索引从0开始,从它开始报数。
#include "sprites.h" //包含C++精灵库
using namespace std;
Screen screen;
int main(){ //主功能块
screen.bgcolor("black");
//bubble0.png是红色的圆圈,上面有0,这些圆圈是用另一个程序生成的,如果没有,请自行生成
//bubble1.png是橙色的圆圈,上面有1,其它依次类推,圆形颜色的色相相隔36。
vector<string>shapes = {"res/bubble0.png","res/bubble1.png","res/bubble2.png","res/bubble3.png","res/bubble4.png","res/bubble5.png","res/bubble6.png","res/bubble7.png","res/bubble8.png","res/bubble9.png"};
vector<Sprite*> persons;
for(int i=0;i<10;i++){ //生成10个角色,用不同颜色的圆圈代替
Sprite* j = new Sprite(shapes[i]);
j->setheading(360-i*36+90); j->penup();
j->fd(160);j->setflag("alive");j->seth(0);
persons.push_back(j);
}
Sprite bao{"blank"}; //在最上面写报数的数字的1,2,3的
bao.penup().sety(330).color("red");
Sprite pen{"blank"}; //无造型的角色,用于报告谁出队了
pen.penup().sety(250).color("magenta");
//新建箭头造型的角色ptr
Sprite ptr{"res/pointer_blue.png"}; //在中间的蓝色的指示器,谁报到3了,就会出队,先把角色变成透明效果来表示
ptr.seth(90); //初始方向指向0号角色(红色的上面写0的圆圈)
bool diedflag[10]={false}; //描述是否出队的布尔数组
int baoshu= 0; //报数器
int cntdied = 0; //统计出队的人数
vector<int> seq; //保存出队顺序
while(cntdied<10){
for(int i=0;i<10;i++){
if(diedflag[i]==true)continue; //此人已死,下一个
baoshu++;
ptr.setheading(360-i*36+90);
bao.cleartxts(1).write(to_string(baoshu),40); //最上面显示1,2,3
delay(1);
if(baoshu==3){
seq.push_back(i);
persons[i]->setalpha(50); //透明,表示已死
string s = "编号" + to_string(i) +"已死";
pen.cleartxts(1).write(s,33).wait(1);
diedflag[i]=true; baoshu=0; cntdied++; //死亡人数增加1
pen.cleartxts(1);
}
}
}
bao.cleartxts(1).write("出队序列",40);
//最终出队顺序是2 5 8 1 6 0 7 4 9 3 ,下面可视化的显示这个序列
for(int i=0;i<10;i++){
persons[seq[i]]->stamp(); //在原位置盖图章
persons[seq[i]]->setalpha(255); //恢复alpha通道为255
persons[seq[i]]->go(-200 + i*50,250); //定位到上面去排成一行,从而可视化显示出队序列
}
screen.done(); //完成了
return 0; //返回0
}