c语言报数问题

c语言报数问题,第1张

设有n个人围坐一圈并按顺时针方向从1到n编号,从第s个人开始进行1到m的报数,报数到第个m人,此人出圈,再从他的下一个人重新开始1到m的报数,如此进行下去直到所有的人都出圈为止。现要求按出圈次序,每10人一组,给出这n个人的顺序表。请考生编制函数Josegh()实现此功能并调用函数WriteDat()把结果p输出到文件OUT.DAT中。

设n=100,c=1,m=10.

(1)将1到n个人的序号存入一维数组p中;

(2)若第i个人报数后出圈,则将p[i]置于数组的倒数第i个位置上,而原来第i+1个至倒数第i个元素依次向前移动一个位置;

(3)重复第(2)步直至圈中只剩下p[1]为止。

部分源程序已给出。

请勿改动主函数main()和输出数据函数writeDat()的内容。 #include <stdio.h>

#define N 100

#define S 1

#define M 10int p[100],n,s,m

void WriteDat(void)void Josegh(void)

{}void main()

{

m=M

n=N

s=S

Josegh()

WriteDat()

}void WriteDat(void)

{

int i

FILE *fp

fp=fopen("out.dat" ," w" )

for(i=N-1i>=0i--){

printf(" %4d" ,p[i])

fprintf(fp," %4d" ,p[i])

if(i % 10==0){

printf("\n" )

fprintf(fp, "\n" )

}

}

fclose(fp)

}

/* 注:题中第一个for()循环是先对数组p赋初值。在第二个for()中用i来控制没出圈的

总人数,s1=(s1+m-1)%i的作用是找出报数后出圈人的下标,其中对i求余的作用是使报

数按圈进行(即报到尾后又从头报),该算法在很多题目中都用到。由于求余的作用当

报数正好到最后一个时s1为0,故而要进行if(s1==0)的判断。内嵌的for()循环是将出圈

以后的人依次往前移。*/

void Josegh(void)

{

int i,j,s1,w

s1=s

for(i=1i<=ni++)

p[i-1]=i

for(i=ni>=2i--)

{s1=(s1+m-1)%i<br>if(s1==0)<br>s1=i<br>w=p[s1-1]<br>for(j=s1j<ij++)<br>p[j-1]=p[j]<br>p[i-1]=w<br>}

} 这的问题和这个一样,看看吧,应该能解决了

法一(模拟法):

#include<iostream>

using std::cin

using std::cout

int main()

{

    int n,m

    cout<<"请输入n= "

    cin>>n

    if(n<1)

        {

        cout<<"n必须大于1!\n请重新输入n= "

        cin>>n

        }

    cout<<"请输入m= "

        cin>>m   

    bool * a = new bool [n+1]

    a[0]=false

    for(int i=1i<n+1i++)

    a[i]=true

    int x,k=nx=i=0//i为每次循环计数变量,x为人员序号,K为剩余人数

    while(k!=0)

    {

    x++

    if(x>n) x=1//当人员到达数组尾,序号重设为1

    if(a[x])i++ // 跳过已退出人员

    if(i==m)

    {a[x]=falsei=0k--}//当数到m时,退出人员设为false,剩余人数减1,i设为0,重新计数

    }

    cout<<"留下来的人序号为: "<<x<<"\n"

    delete [] a

    cin.get()

    cin.get()//等待下一次键击关闭窗口

    return 0

}

法二(递归法):

此题可用数学方法求解。

设有n个人(编号0~(n-1)),从0开始报数,报到(m-1)的退出,剩下的人继续从0开始报数    (用数学方法解的时候需要注意应当从0开始编号,因为取余会取到0解。)

实质是一个递推,n个人中最终留下来的序号与n-1个人中留下来的人的序号有一个递推关系式。

假设除去第k个人,则

0, 1, 2, 3, ..., k-2, k-1, k, ..., n-1          // 原始序列 (1)

0, 1, 2, 3, ..., k-2,      , k, ..., n-1      // 除去第k人,即除去序号为k-1的人   (2)

k, k+1, ..., n-1,    0,    1,        ..., k-2// 以序号k为起始,从k开始报0  (3)

0, 1,     ..., n-k-1, n-k, n-k+1, ..., n-2   // 作编号转换,此时队列为n-1人  (4)

变换后就完完全全成为了(n-1)个人报数的子问题,注意(1)式和(4)式,是同一个问题,不同的仅仅是人数。比较(4)和(3),不难看出,0+k=k, 1+k=k+1, ... ,(3)式中'0'后面的数字,

((n-3)+k)%n=k-3,((n-2)+k)%n=k-2, 对于(3)式中'0'前面的数字,由于比n小,也可看作(0+k)%n=k,  (1+k)%n=k+1,  故可得出规律:

设(3)中某一数为x' , (4)中对应的数为x,则有:x'=(x+k)%n.

设x为最终留下的人序号时,队列只剩下1人时,显然x=0此时可向前回溯至2人时x对应的序号,3人时x对应的序号……直至n人时x的序号,即为所求。

#include <iostream>

using namespace std

int main()

{

    int n,m,f=0

    cin>>n>>m

    for(int i=2i<=ni++) 

    f=(f+m)%i

    cout<<f+1<<endl

}


欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/yw/12073319.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-05-20
下一篇2023-05-20

发表评论

登录后才能评论

评论列表(0条)

    保存