北大oj1012——Joseph

Joseph

Time Limit: 1000MS Memory Limit: 10000K

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

3
4
0

Sample Output

5
30

最终还是过了,真的吐血了,我用链表模拟去从1跑到13也就124ms为啥提交上去还是超时了,非常疑惑,然后参考了大佬的代码,先把1到13的值求出来再一个个输出值就过了,,,真的吐血了,,,~~~
剪枝方法:
1.只有当m为m%(k+1) == 0或者m%(k+2) == 0时才有效,因为当只剩最后两个坏人的时候,若先死的是排名在前面的坏人,那么下一次一定是 k+2的倍数才能数到下一个坏人,若先死的是排名在后面的坏人,那么下一次一定是 k+1 的倍速才能数到下一个坏人。
2.模拟过程一定要取模后再去模拟。
3.首次计算的值一定是k+1,小于等于k的值都不行。
4.最最最重要的,先把1-13的值都求出来后再去根据输入的n来输出值!!!!!!!!!!!!

#include <iostream>
#include <algorithm>
using namespace std;

bool isSuccess;
int k;

struct LinkTable
{
    int _pos;
    LinkTable* next;
    LinkTable(int pos) { this->_pos = pos; };
};

LinkTable* _linkTable;
LinkTable* _startTable;
int totalSize = 0;

void addLinkTable(int pos) {
    if (_linkTable == NULL) {
        _linkTable = new LinkTable(pos);
        _linkTable->next = _linkTable;
        _startTable = _linkTable;
    }
    else {
        LinkTable* newLinkTable = new LinkTable(pos);
        newLinkTable->next = _linkTable->next;
        _linkTable->next = newLinkTable;
        _linkTable = newLinkTable;
    }
}

int start(int last, int num, LinkTable* startPos) {
    if (last <= 0) {
        isSuccess = true;
        return 1;
    }

    int useNum = (num - 1) % totalSize + 1;
    int pos;
    LinkTable* lastPos = startPos;
    if (useNum == 1) {
        useNum += totalSize;
    }
    while (useNum != 0) {
        useNum--;
        if (useNum == 1) {
            lastPos = startPos;
        }
        if (useNum != 0) {
            startPos = startPos->next;
        }
    }
    pos = startPos->_pos;
    if (pos <= k) {
        return 0;
    }
    else
    {
        lastPos->next = startPos->next;
        totalSize--;
        start(last - 1, num, startPos->next);
    }

    lastPos->next = startPos;
}

int main() {
    int allResult[14];
    for (int n = 1; n < 14; n++) {
        k = n;
        _linkTable = NULL;
        for (int i = 1; i <= n * 2; i++) {
            addLinkTable(i);
        }
        isSuccess = false;
        int num = n;
        while (!isSuccess) {
            num++;
            if (!(num % (n + 1) == 0 || num % (n + 1) == 1)) {
                continue;
            }
            totalSize = n * 2;
            start(n, num, _startTable);
        }
        allResult[n] = num;
    }

    int n;
    while (cin>>n && n)
    {
        cout << allResult[n] << endl;
    }

    return 0;
}

以下是通过的方法,没用链表,直接用数组去循环的。

#include <iostream>
using namespace std;

int start(int last, int num) {
    int i = 0;
    int j = 0;
    for (i = 0; i < last; i++) {
        j = (j + num - 1) % (2 * last - i);
        if (j < last) {
            return 0;
        }
    }
    return 1;
}

int main() {
    int allResult[14];
    for (int i = 1; i < 14; i++) {
        int num = i;
        while (true) {
            num++;
            if (!(num % (i + 1) == 0 || num % (i + 1) == 1)) {
                continue;
            }
            int result = start(i, num);
            if (result) {
                break;
            }
        }
        allResult[i] = num;
    }

    int n;
    while (cin>>n && n)
    {
        cout << allResult[n] << endl;
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

椰子糖莫莫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值