***问题

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;

}

 

全部评论

相关推荐

在评审的大师兄很完美:像这种一般就是部门不匹配 转移至其他部门然后挂掉 我就是这样被挂了
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务