***问题
17 世纪法国数学家加斯帕在《数学的游戏问题》中讲的一个故事:n个***和n个非***在深海上遇险,必须将一半的人投入海中,其余的人才能幸免于难,于是想了个办法:2n 个人围成一个圆圈,从第一个人开始依次循环报数,每数到第九个人就将他扔入大海,如此循环直到仅剩 n 个人为止。问怎样的排法,才能使每次投入大海的都是非***。
【输入】输入文件由一行构成,就是 n 的值。
【输出】输出文件中是一行字符串,字符串由 n 个‘@’字符(代表***)和 n 个‘+’字符(代表非***)排列构成。该排列使得按照前面的约定每次投入大海的都是非***。
【输入范例】 15
【输出范例】 @@@@+++++@@+@@@+@++@@+++@++@@+
程序代码:
#include<stdio.h>
#include<stdlib.h>
typedef struct LNode
{
intdata; //表示该元素的编号
structLNode *next;
}LNode,*LinkList; //结点类型,指针类型
int main()
{
intn; //n表示总人数的一半
scanf("%d",&n); //输入n
inti;
intpre=0; //pre用来计数,每删除一个就加1
char*j; //定义一个字符型指针,用来存储表示***和非***的符号
j=(char*)malloc(sizeof(char)*2*n); //为指针j申请动态存储空间,长度为2*n
LinkListlist=NULL,p,r; //初始化链表为空,p为当前结点r的辅助结点,指向p的前驱结点list为头结点
for(i=1;i<=2*n;i++) //建立循环链表
{
p=(LinkList)malloc(sizeof(LNode)); //申请新结点
p->data=i; //给结点的数据域赋值为i
if(list==NULL) //判断,如果链表为空,就将头结点指向p
list=p;
else //否则,将结点p赋给r的next,是链表逐渐加长
r->next=p;
r=p; //将结点p赋给r
}
p->next=list; //使循环链表循环起来
p=list; //使p指向头结点
while(p->next!=p) //循环的删除队列链表
{
for(i=1;i<9;i++) //每到第9个时,将p的next赋给r的next
{
r=p;
p=p->next; //不到第9个时,就依次向后遍历
}
r->next=p->next;
pre=pre+1; //每到第9个时,记一次数
if(pre-n<=0) //判断,每删除一个,就把表示非***的'+'赋给指针j,并记录其位置p的data
{
*(j+p->data)='+';
}
else //如果删除的人超过n个后,就把表示***的'@'赋给指针j,并记录其位置p的data
{
*(j+p->data)='@';
}
free(p); //每次结束后释放结点p的空间
p=r->next; //让p指向r的next,进行下轮删除
}
*(j+p->data)='@'; //全部删除完后,将最后一个表示***的'@'赋给指针j,并记录其位置p的data
for(i=1;i<=2*n;i++) //循环,读取指针j中存储的元素,依次输出
{
printf("%c",*(j+i));
}
printf("\n");
return0;
}