就是经典约瑟夫环问题的裸题

我一开始一直没理解这个递推是怎么来的,后来终于理解了

假设问题是从n个人编号分别为0...n-1,取第k个,

则第k个人编号为k-1的淘汰,剩下的编号为  0,1,2,3...k-2,k,k+1,k+2...

此时因为从刚刚淘汰那个人的下一个开始数起,因此重新编号

把k号设置为0,则

k    0

k+1 1

...

0 n-k

1 n-k+1

假设已经求得了n-1个人情况下的最终胜利者保存在f[n-1]中,则毫无疑问,该胜利者还原到原来的真正编号即为 (f[n-1]+k)%n (因为第二轮重新编号的时候,相当于把每个人的编号都减了k,因此重新+k即可恢复到原来编号)。由此,我们可以想象,当最终只剩下一个人的时候,该人即为胜利者,此时重新编号,因为只有一个人,所以此时f[1]=0

这样f[2]=(f[1]+k)%2,这样就可以求出最终胜利者在2个人的时候的情况下的编号,由递推公式f[n]=(f[n-1]+k)%n,可递推到最初编号序列中该胜利者的编号。

因此用这个方法,只需一遍On的扫描,即可求出最终答案

不过该题要求编号从1开始,只要把f[n]+1即可,同时,该题指定了第一个要删除的人必须为编号为m的人,其实也不难,求出f[n]之后,把原本编号为0的位置移到跟m只相距k的位置即可实现第一次删除的编号为m。所以最终 ans=(f[n]+1+m-k);

当然因为m-k可能为负数,导致整个ans为负,这样其实最后+n即可解决。

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int n,m,k;
int main()
{
while (scanf("%d%d%d",&n,&k,&m))
{
if (n+m+k==) break;
int s=;
for (int i=;i<=n;i++)
s=(s+k)%i;
int ans;
ans=(m-k+s+)%n;
if (ans<=) ans+=n;
printf("%d\n",ans);
}
return ;
}

最新文章

  1. SVProgressHUD
  2. jQuery 事件探秘
  3. 数据库连接池配置 - Oracle,SQL Server,DB2,MYSQL,SQLLITE3
  4. 网站后台调用winform MessageLoopApartment
  5. 基于HTML5的Web跨设备超声波通信方案
  6. 应用程序代理AppDelegate解析
  7. popupWindow弹出来后,背景变暗,半透明
  8. PHP组合模式
  9. CC2640-之功耗
  10. HTML5:基本使用
  11. (三)backbone - API学习 - v0.9.2 与 v1.1.2区别
  12. IPV6与IPV4的区别
  13. 如何使用sourcetree 或 IDEA 自带的git合并代码?
  14. 深入理解Postgres中的cache
  15. BSA Network Shell系列-scriptutil命令
  16. 转)sqlite 数据类型
  17. 19.最省钱的app发短信方法
  18. PAT之写出这个数
  19. python requests简介
  20. rename批量修改文件并在后缀前加字段

热门文章

  1. python基础(变量,字符串,列表,元组)
  2. [CSS]水平垂直居中方案
  3. css 径向渐变
  4. UVA - 11212 Editing a Book(IDA*算法+状态空间搜索)
  5. 19 01 17 Django 模板 返回一个页面
  6. C++ STD Gems03
  7. swiper实现匀速无缝滚动
  8. (5)opencv的基础操作和矩阵的掩模操作
  9. SrpingMVC/SpringBoot中restful接口序列化json的时候使用Jackson将空字段,空字符串不传递给前端
  10. 2016蓝桥杯省赛C/C++A组第三题 方格填数