- UID
- 6266
- 精华
- 积分
- 794
- 威望
- 点
- 宅币
- 个
- 贡献
- 次
- 宅之契约
- 份
- 最后登录
- 1970-1-1
- 在线时间
- 小时
|
本帖最后由 new_starter 于 2020-11-1 22:01 编辑
约瑟夫环问题起源于一个犹太故事。
传说罗马人攻占了乔塔帕特,41个人藏在山洞中躲过了这场浩劫。这41人中包括历史学家Josephus约瑟夫和他的一个朋友。剩余的39人为了表示绝不屈服于罗马人于是决定集体自杀。所有这41人围成圈由第一个人开始顺时针报数,每报数为3的人就立刻自杀,然后再由下一个人重新开始报数,仍然是每报数为3的人就立刻自杀,直到所有人都死亡为止。
约瑟夫和他的朋友并不想自杀。于是约瑟夫想到了一个计策,他们两人同样参与到自杀方案中,但是最后却躲过了自杀。
下面的程序给出了约瑟夫环的解法,注意该程序需要StoneValley库的支持:
- #include <stdio.h>
- #include "../src/svstring.h"
- // Function: cbftvs_print_list
- // Desc: Print item number in linked-list.
- // Param: pitem: pointer to each node in a list. param: N/A.
- // Return: CBF_CONTINUE only.
- int cbftvs_print_list(void * pitem, size_t param)
- {
- printf("%ld, ", *(long *)((P_NODE_D)pitem)->pdata);
- DWC4100(param);
- return CBF_CONTINUE;
- }
- // Function: main
- // Desc: Program entry.
- // Param: N/A.
- // Return: 0: no error. 1: allocation failure.
- int main(void)
- {
- char c;
- long i, j;
- LIST_D jring;
- P_NODE_D pnew, pnode;
- const char * sfx[] = { "m", "ms", "is", "are" };
- strInitLinkedListDC(&jring);
- pnode = jring;
- printf("# A solution to Josephus's ring. <"); svPrintVersion(); printf("> #\n");
- Lbl_Start:
- do
- {
- printf("How many items will be there in a ring? ");
- scanf("%ld", &j);
- }
- while (j < 1);
- for (i = 1; i <= j; ++i)
- {
- if (NULL == (pnew = strCreateNodeD(&i, sizeof(long))))
- {
- puts("Error! Allocation failure while building ring.");
- strFreeLinkedListDC(&jring, FALSE);
- return 1; /* Allocation failure. */
- }
- if (NULL != pnode)
- {
- pnode->ppnode[NEXT] = pnew;
- pnew->ppnode[PREV] = pnode;
- }
- else
- jring = pnew;
- pnode = pnew;
- }
- /* Make a ring. */
- pnode->ppnode[NEXT] = jring;
- jring->ppnode[PREV] = pnode;
- do
- {
- printf("\tNow, there %s %ld ite%s in the ring.\nWhich number would you like \
- to choose to delete ite%s sequentially? ", sfx[(j > 1) + 2], j, sfx[j > 1], sfx[j > 1]);
- scanf("%ld", &i);
- }
- while (i < 1);
- for ( ;; )
- {
- pnode = strLocateItemDC_R(jring, i - 1);
- if (jring != pnode)
- {
- jring = pnode->ppnode[NEXT];
- strRemoveItemLinkedListDC(pnode);
- printf("\tRemove: %ld\n", *(long *)pnode->pdata);
- strDeleteNodeD(pnode);
- }
- else
- break;
- }
- if (NULL != pnode)
- {
- printf("The rest of ite%s in the ring %s labeled with: ",
- sfx[jring != jring->ppnode[NEXT]], sfx[(jring != jring->ppnode[NEXT]) + 2]);
- strTraverseLinkedListDC_X(jring, NULL, cbftvs_print_list, 0, FALSE); puts("\b\b.");
- }
- strFreeLinkedListDC(&jring, FALSE);
- pnode = NULL;
- do
- {
- fflush(stdin);
- printf("Would you like to continue playing(Y/n)? ");
- scanf("%c", &c);
- switch (c)
- {
- case 'Y': case 'y': goto Lbl_Start;
- case 'N': case 'n': return 0;
- }
- }
- while (c != 'Y' && c != 'y' && c != 'N' && c != 'n');
- return 0;
- }
复制代码
程序运行结果如下:
该程序的核心是strLocateItemDC_R函数,使用该函数可以向前、向后定位循环双向链表上的任意一个节点。
|
|