zoukankan      html  css  js  c++  java
  • 【约瑟夫环变形】UVa 1394

    首先看到这题脑子里立刻跳出链表。。后来继续看如家的分析说,链表法时间复杂度为O(n*k),肯定会TLE,自己才意识到果然自个儿又头脑简单了 T^T.

    看如家的分析没怎么看懂,后来发现这篇自己理解起来更容易(...)共享一下~http://blog.csdn.net/chenguolinblog/article/details/8873444

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

    编号0~(n-1)是有意义的,因为要模n,所以用0-(n-1)更好操作
    我们知道第一个人(编号一定是(m-1) mod n) 出列之后,剩下的n-1个人组成了一个新的约瑟夫环(以编号为k=m mod 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
    变换后就完完全全成为了(n-1)个人报数的子问题,假如我们知道这个子问题的解:例如x是最终的胜利者,那么根据上面这个表把这个x变回去不刚好就是n个人情况的解吗?!!变回去的公式很简单,相信大家都可以推出来:x'=(x+k) mod n;

    所以我们只要一直重复这个过程便能求得最开始那个人的编号,因为这个人最终的编号是0(只剩他一个人):0->(0+k)%2->((0+k)%2+k)%3->......
    f[n]=(f[n-1]+k)%n,f[1]=0;  f[i]表示有i个人时,最后胜利者编号

    ==========================================

    注意此上思路就适用于经典约瑟夫环问题。

    ==========================================

    下面就要变形了...

    现在这个问题是从m开始,即是首先(m-1)编号的人出去。。然后就和普通约瑟夫环一样了。故只要我们f[n]=(f[n-1]+m)%n单独算就行了。其他f[i]=(f[i-1]+k)%i;(1<i<n);

    代码如下:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstdlib>
     4 #include<cstring>
     5 using namespace std;
     6 const int maxn = 10005;
     7 int f[maxn];
     8 int main()
     9 {
    10     int n, k, m, step, cnt;
    11     while(~scanf("%d%d%d", &n, &k, &m))
    12     {
    13         if(!n && !k && !m)   break;
    14         f[1] = 0;
    15         for(int i = 2; i < n; i++)
    16         {
    17             f[i] = (f[i-1]+k)%i;
    18         }
    19         int ans = (f[n-1]+m)%n;
    20         printf("%d
    ", ans+1);
    21     }
    22     return 0;
    23 }
  • 相关阅读:
    在酷热的就业天气寻找几丝凉意
    《Orange ’ s :一个操作系统的实现 》作者自序
    Windows的设备驱动框架
    Windows的设备驱动框架中的上层与下层模块
    如何搭建自己的开发环境
    数据库设计指南(二)设计表和字段
    软件敏捷架构师
    Struts到JSF/Tapestry
    敏捷开发
    barcode制作条形码及破解
  • 原文地址:https://www.cnblogs.com/LLGemini/p/4311879.html
Copyright © 2011-2022 走看看