码迷,mamicode.com
首页 > 其他好文 > 详细

POJ 1012 Joseph

时间:2015-04-25 12:12:01      阅读:125      评论:0      收藏:0      [点我收藏+]

标签:

题意:有k个好人和k个坏人进行约瑟夫环问题,好人在前面,坏人在后面(即好人编号为0...k - 1),求一个最小的m,使他们用m报数时所有坏人在有好人出局之前出局

 

解法:一开始没怎么细想就写了个模拟……果断T了……于是想把结果打表……结果发现k = 13时根本跑不完……

于是还是枚举m,推导每次出局的人,并在线打表。

以n = 6, m = 5举例:

一开始序列为0, 1, 2, 3, 4, 5

第m%n个人出局,对应的编号为(m + 1) % n

从出局后面的人开始报数,则队列变为:

5, 0, 1, 2, 3重新编号则变为:

0, 1, 2, 3, 4

此时人数n减少了1

则第m%(n - 1)个人出局,对应的编号为(m + 1) % (n - 1)

设上一轮出局的人编号为x,本轮编号从上一轮出局的人的后一人开始,所以反推回去本轮出局的(m + 1) % (n - 1)在上一轮的编号为(x + (m + 1) % (n - 1)) % (n - 1)

化简得到(x + m + 1) % (n - 1)

这是对于第二轮来说的,每轮的人数都会减少,第k轮的时候人数为n - k + 1

所以最终的通项公式为f[0] = 0, f[i] = (f[i - 1] + m + 1) % (n - k + 1),f[i]的含义为第i轮出局的人的编号

那么只要判断前k轮有没有好人出局就可以了,一旦有好人出局则继续枚举m,没有好人出局则为答案

 

代码:

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string>
#include<string.h>
#include<math.h>
#include<limits.h>
#include<time.h>
#include<stdlib.h>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
#define LL long long
using namespace std;
int main()
{
    int jos[14] = {0};//在线打表,避免反复求解
    int n;
    while(~scanf("%d", &n) && n)//n即为上面说的k,2 * n为上面说的n(变量名起的这么奇幻真的好么)
    {
        if(jos[n])
        {
            printf("%d\n", jos[n]);
            continue;
        }
        int m = 1;
        while(1)
        {
            int f = 0;
            int i = 1;
            for(; i <= n; i++)
            {
                f = (f + m - 1) % (2 * n - i + 1);
                if(f < n)
                {
                    m++;
                    break;
                }
            }
            if(i > n)
            {
                jos[n] = m;
                printf("%d\n", m);
                break;
            }
        }
    }
    return 0;
}

  

POJ 1012 Joseph

标签:

原文地址:http://www.cnblogs.com/Apro/p/4455626.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!