hdu 1443 Joseph(约瑟夫环+枚举)

来源:互联网 发布:js获取所有id 像 编辑:程序博客网 时间:2024/06/04 19:15

Joseph

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 1811    Accepted Submission(s): 1113


Problem Description
The Joseph's problem is notoriously known. For those who are not familiar with the original problem: from among n people, numbered 1, 2, . . ., n, standing in circle every mth is going to be executed and only the life of the last remaining person will be saved. Joseph was smart enough to choose the position of the last remaining person, thus saving his life to give us the message about the incident. For example when n = 6 and m = 5 then the people will be executed in the order 5, 4, 6, 2, 3 and 1 will be saved.

Suppose that there are k good guys and k bad guys. In the circle the first k are good guys and the last k bad guys. You have to determine such minimal m that all the bad guys will be executed before the first good guy.
 

Input
The input file consists of separate lines containing k. The last line in the input file contains 0. You can suppose that 0 < k < 14.
 

Output
The output file will consist of separate lines containing m corresponding to k in the input file.
 

Sample Input
340
 

Sample Output
530
 

Source
ACM暑期集训队练习赛(5)
 题目分析:约瑟夫环模板题
首先想到的是用链表模拟,然后枚举,果然超时了
#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;struct Point{    int pre;    int next;    int id;}p[50];int start , eend , n;int main ( ){    while ( ~scanf ( "%d" , &n ) , n )    {        int m = n;        while ( m )        {            start = 0 , eend = 2*n-1;            p[eend].next = start;            p[eend].id = 2*n;            p[eend].pre = 2*n-2;            for ( int i = 0 ; i < 2*n-1 ; i++ )            {                if ( i == 0 ) p[i].pre = eend;                else p[i].pre = i-1;                p[i].next = i+1;                p[i].id = i+1;            }            int cur = start;            bool flag = false;            int lim = m%(2*n);            for ( int i = 0 ; i < n ; i++ )            {                for ( int i = 1 ; i < m ; i++ )                    cur = p[cur].next;                if ( p[cur].id <= n )                 {                    m++;                    flag = true;                    break;                }                int id1 = p[cur].pre , id2 = p[cur].next;                p[id1].next = id2;                p[id2].pre = id1;                cur = id2;            }            if ( flag ) continue;            else printf ( "%d\n" ,  m );            break;        }    }}

后来想到了数学的优化方法,每次我们只能找到坏人,也就是找到i>n位置的人,因为每次去掉一个坏人后,每个坏人是无区别的,所以直接将当前环转变为2*n-1的环,然后找到的依旧不能在前n个
f[1] = m;
f[i] = (f[i]+m-1)%n
继续枚举,轻松过掉
#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;int n;int ret[20];int solve (  int n ){    if ( ret[n] ) return ret[n];    int ans = n+1,sum;    while ( ans )    {        sum = 2*n;        for ( int i = ans ; ; i += ans-1 )        {            if ( i > sum )                i = i%sum?i%sum:sum;            if ( i <= n )                break;            else sum--;            if ( sum == n ) break;        }        if ( sum == n )            return ret[n] = ans;        ans++;     }}int main ( ){    memset ( ret , 0 , sizeof ( ret ) );    while ( ~scanf ( "%d" , &n ),n )    {        printf ( "%d\n" , solve ( n ) );    }}


0 0
原创粉丝点击