北大ACM(1012Joseph)程式碼
阿新 • • 發佈:2018-12-19
/*
Memory 92K Time 47MS
*/
#include <stdio.h>
#include <stdlib.h>
/*
解約瑟夫問題
假如存在n個人 其中有k個壞人k個好人 每隔m個月就殺掉一個人,你需要保證所有的壞人都在好人前面被殺掉
並且最後剩下一個好人
現在要求你輸入 k 其中前一個k的數量表示好人的數量 後一個k表示壞人的數量
然後輸出與k對應的最小m
*/
/*
計算出 約瑟夫問題的公式為
(m + start -1) % (n - killCount)
(輪數m + 開始下標start - 1) % (數字總數n - 以及被kill的數字數量killCount)
獲取下一輪被kill的數字下標,其中下標不為實際上的下標 而是跳過被kill的number 的下標
也就是當前剩餘數的下標
*/
#define MAX_SIZE 14
int calc(int m, int n);
int main()
{
int gResult[MAX_SIZE]; //儲存題目要求的1-13個數字對應的結果
int m, k;
for (k = 1; k < MAX_SIZE; ++k)
{
m = k + 1; //對於給定一個數字 它的週期數不會少於自身+1
while (1)
{
if (calc(m, k * 2))
{
gResult[k - 1] = m;
break;
}
else if (calc (m + 1, k * 2))
{
gResult[k - 1] = m + 1;
break;
}
m += k + 1; //每次將輪數m遞增 增長率至少為 k
}
}
while (scanf_s("%d", &k) && k)
{
printf_s("%d\n", gResult[k - 1]);
}
return 0;
}
int calc(int m, int n) //對於給定的m輪數來計算出是否能夠滿足數字總數n的要求
{
int killCount = 0;
int start = 0; //每次開始的下標
///迴圈進行檢測 如果出現了下標小於 n / 2表示該m為不可行方案 直接返回假
while (n - killCount > n / 2)
{
start = (m + start - 1) % (n - killCount);
if (start < n / 2) return 0;
killCount++;
}
return 1;
}