自我探讨 国王和狱吏(合数)

课堂上老师提到的一个问题:

   某国王对囚犯进行大赦,让一狱吏n次通过一排锁着的n间牢房,每通过一次,按所定规则转动n间牢房中的某些门锁, 每转动一次, 原来锁着的被打开, 原来打开的被锁上;通过n次后,门锁开着的,牢房中的犯人放出,否则犯人不得获释。
    转动门锁的规则是这样的,第一次通过牢房,要转动每一把门锁,即把全部锁打开;第二次通过牢房时,从第二间开始转动,每隔一间转动一次;第k次通过牢房,从第k间开始转动,每隔k-1 间转动一次;问通过n次后,哪些牢房的锁仍然是打开的?


【思路分析】

   如果用暴搜的话对于大数据肯定会跪,因此还有进一步优化的方法。

   分析的时候会发现每次转动门锁只是改变原有的状态,即state = ! state,而且一开始的状态均为state = false,那么转动这个门锁次数的奇偶性决定了门锁最终的状态。由于先后转动门锁的编号依次为1k,2k,3k,。。。。,所以门锁编号的合数的个数便是总共转动的次数。例如2号门锁转动2次,因为合数为1,2,12号门锁转动6次,因为合数为1,2,3,4,6,12,16号门锁转动5次,因为其合数为1,2,4,8,12(4只算一次),由此可得出规律:当i为完全平方数时,转动编号i门锁的次数为奇数,那么最终编号i的牢房是打开的。这个规律也很好证明:一个数a若能整除一个整数b,令c = b / a,则c要么和a相等要么和a不等,如果不等的话合数计为两个(一定成双出现),如果相等的话合数只计一个(即b为完全平方数的情况),则可以得出上述结论。


代码如下:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
const int maxn = 1005;
int n,sum;
int ans[maxn];
void init()
{
    sum = 0;
}
void solve(int n)
{
    for(int i = 1;i <= n;i++)
    {
        if(i * i <= n)
        {
            ans[sum] = i * i;
            sum++;
        }
        else
        {
            break;
        }
    }
    printf("The sum of out people is : %d\n",sum);
    printf("The numbers of out people are :\n");
    for(int i = 0;i < sum;i++)
    {
        printf("%d\n",ans[i]);
    }

}
int main()
{
    int n;
    while(scanf("%d",&n) && n != 0)
    {
        init();
        solve(n);
    }
    return 0;
}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值