约瑟夫问题

本文深入探讨了约瑟夫问题的解决策略,通过逆向思维的方法,提出了一个有效算法来确定初始牌的排列顺序。该算法利用环状循环特性,确保按照指定顺序翻牌,实现高效解决问题的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

假设有问题如下:

步骤:
  1.有牌面上写着从1到N的N张纸牌按照一定的顺序放在桌子上。
  2.把此时最上面的一张牌放到纸牌的最下面去。
  3.翻开此时最上面的一张牌,出现的是数字“1”。
  4.把这张牌放到一边去。
  5.把此时最上面的一张牌放到纸牌的最下面去。
  6.翻开此时最上面的一张牌,出现的是数字“2”。
  7.把这张牌放到一边去。
  8.以此类推,每次都把最上面的牌放到最下面,再翻开最上面的一张牌。使得翻开的牌,是按照1到N的顺序出现。

问题:
  在第一步当中,要如何排列这N张牌,可以做到这样的效果?

 

拿到这个问题,大家顿时傻眼了,不知如何下手。其实这就是约瑟夫问题~

逆向思维,假设我们已经知道初始时候牌的排列顺序,记录在数组D[]中,我们按照上述步骤以此翻牌,每个步骤对应的数据索引是已知的,而当前翻开的牌应该是多少也是固定要求的,因此当前索引对应的值就是固定的。因此,最终我们的数组D就确定了。

 

void calculate() {
    int Answer[N] = {0};
    int numZero = 0;
    int index = -1;
    int count = 1;
    while (count <= N) {
        do {
            index = (index + 1) % N;     // 环状循环
            if (Answer[index] == 0) {    // 发现了空位置0,  numZero加1 
                numZero++;
            }
            if (numZero == 2) {             // 发现了第2个空位置0,跳出循环
                numZero = 0;
                break;
            }
        } while(1);
        Answer[index] = count;          // 第2个空位置翻牌“自杀”。 count加1
        count++;
    }
}

 

值的注意的是,上述代码中出现了环状循环,大家需要熟悉它的用法。


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值