注册 登录
编程论坛 VFP论坛

也来发一个算法问题,其实是小学生的课后思考题.

厨师王德榜 发布于 2021-03-17 10:44, 2745 次点击
也来发一个算法问题,其实是小学生的课后思考题.
我自己做起来很懵逼......
题目如下:
有九个同学,姑且给他们背后贴上纸条,纸条上编号分别为:A,B,C...I
让他们站成一个圆圈,由A同学开始,从1开始报数,
当有同学报"5"时,这个同学退出圈子.
这个同学之后的一个同学,重新开始从1开始报数,
当有同学报"5"时,这个同学退出圈子.周而复始...
......
直到剩下最后一个同学.
问:这个同学,背后纸条上编号为?

头脑里过一遍,或者纸面上写写画画,或许能找到答案,
但是我要的不是答案,而是过程,而且把这个过程,用程序语言描述出来.

程序运行后,希望输出这样的效果:
第1轮,E同学退出...
第2轮,A同学退出...
...
第?轮,?同学退出...至此,只剩下最后一位?同学.


欢迎各位用你们擅长的编程语言来求得答案,并展示过程.
15 回复
#2
sdta2021-03-17 11:01
最后剩下的是四个同学,而不是剩下一个同学
只有本站会员才能查看附件,请 登录


[此贴子已经被作者于2021-3-17 11:12编辑过]

#3
厨师王德榜2021-03-17 11:44
同学是站成一个圆圈的,所以当一个同学报到4,而他恰好在圈尾时,下一个同学自动按圆圈的法则,轮下去.
比如第6轮,B同学报4,那么就轮到F同学报5了.即便他在本轮已经报过1,此时也轮到他继续报数.

[此贴子已经被作者于2021-3-17 11:48编辑过]

#4
sdta2021-03-17 11:56
是不是这个意思
只有本站会员才能查看附件,请 登录


[此贴子已经被作者于2021-3-17 12:14编辑过]

#5
厨师王德榜2021-03-17 13:39
回复 4楼 sdta
对的。
#6
厨师王德榜2021-03-17 15:49
我自己写的代码很笨重,主要是搜索下一开始位置时,是逐行扫描的,效率不高.
而且,我没有用数组,用的游标,因为在vfp环境下,我认为没有哪个数组能比游标效率更高了.
如果你用C,VB,java,Python,用数组/列表 这些模型,都可以讨论.
我的代码如下:
程序代码:
CLEAR
CLOSE TABLES ALL
CREATE CURSOR TT (ID i ,cname c(1) ,XH I ,ALIFE L,memo1 c(20))
LOCAL II AS Integer ,icnt as Integer ,ilc as Integer ,ilocate as Integer

* 建立初始模型,顺便模拟首轮排序。
FOR II = 65 TO 73
    INSERT INTO TT (ID,cname,XH,ALIFE) VALUES (II - 64,CHR(II) ,II - 64,.T.)
ENDFOR

ilc =1  && 第?轮
SELECT tt
COUNT FOR alife TO icnt
DO WHILE icnt  > 1
    IF ilc =1 THEN   && 确定开始位置
        ilocate=SetOrder(1)
    ELSE
        ilocate=SetOrder(ilocate)
    ENDIF
    * 处理本轮退出的.
    LOCATE FOR xh = 5 AND alife
    IF FOUND() THEN
        REPLACE alife WITH .f. ,memo1 WITH '' + LTRIM(STR(ilc))  + '轮退出'
        ? '' + LTRIM(STR(ilc))  + '轮,' + cname + '同学退出...下一轮将从ID=' + ;
            LTRIM(STR(ilocate)) + '' + CHR(ilocate + 64) + '同学开始...'
    ELSE
        ? 'Error ... 意外情况'
    ENDIF
    ilc = ilc + 1
    COUNT FOR alife TO icnt
    IF icnt = 1 THEN
        LOCATE FOR alife
        ? '目前在第' + LTRIM(STR(ilc))  + '轮,只剩下' + cname + '同学一人,游戏结束.'
        EXIT
    ENDIF
ENDDO

FUNCTION  SetOrder(startxh) as Integer
* 参数:1开始的位置
LOCAL ncnt as Integer
LOCAL ilot as Integer
LOCAL lfund as Boolean
    SELECT tt
    REPLACE xh WITH 0 FOR  alife
    COUNT FOR  alife TO ncnt
    IF ncnt >1 THEN
        IF startxh > RECCOUNT() THEN
            GO 1
        ELSE
            GO startxh            
        ENDIF
        ii = 1
        DO WHILE ii< 6
            IF  alife THEN
                REPLACE xh WITH ii
                ii = ii + 1
                SKIP
                IF  EOF() THEN
                    GO 1
                ENDIF
            ELSE
            * 后面几轮,会进入这个分支
                SKIP
                IF  EOF() THEN
                    GO 1
                ENDIF                     
            ENDIF
        ENDDO
        * 返回下次应开始的位置:
        LOCATE FOR xh = 5 AND alife
        IF FOUND() THEN
            ilot = id  && 暂时的
            DO WHILE lfund  =.f.
                IF alife AND xh<> 5 THEN
                    ilot = id
                    lfund  =.t.
                ELSE
                    SKIP
                    IF EOF() THEN
                        GO 1
                    ENDIF         
                ENDIF

            ENDDO
            RETURN ilot
        ENDIF     
    ELSE
    * 说明只剩下最后一个了,不再循环,因为没有意义了.
        RETURN 0
    ENDIF

ENDFUNC

#7
schtg2021-03-17 19:12
学习啦,谢谢!
#8
吹水佬2021-03-17 21:59
编程经典“猴子选大王”问题
试试用数组元素轮换
只有本站会员才能查看附件,请 登录

程序代码:
fun(9, 5)
RETURN

FUNCTION fun(n, m)
    DIMENSION arr[9]
    ?
    FOR i=1 TO n
        arr[i] = CHR(i+64)
        ?? " "+arr[i]
    ENDFOR
    DO WHILE n > 1
        FOR i=1 TO m-1
            a = arr[1]
            ADEL(arr,1)
            arr[n] = a
        ENDFOR
        ADEL(arr,1)
        n = n - 1
        **DIMENSION arr[n]
        ?
        FOR i=1 TO n
            ?? " "+arr[i]
        ENDFOR
    ENDDO
ENDFUNC


[此贴子已经被作者于2021-3-17 22:03编辑过]

#9
schtg2021-03-18 05:53
@吹水版主,高!学习啦,谢谢!
#10
吹水佬2021-03-18 10:33
反过来玩又如何,如:
设:有一个乱序的9个同学队列,让他们站成一个圆圈
从第1个同学开始报数,当有同学报"5"时,这个是A同学,出队
这个A同学之后的一个同学,重新开始从1开始报数,当有同学报"5"时,这个是B同学,出队
周而复始.........
直到最后一个是I同学,出队
最后按出队的顺序就是9个同学代号的顺序队列: A B C D E F G H I
求:这个乱序的9个同学队列?


[此贴子已经被作者于2021-3-18 13:59编辑过]

#11
wengjl2021-03-18 11:27
只有本站会员才能查看附件,请 登录

程序代码:
*!*      http://bbs.bccn.net/thread-505144-1-1.html  
*!*     论坛上狐友“厨师王德榜”发的题目
   
*!*    也来发一个算法问题,其实是小学生的课后思考题.
*!*    我自己做起来很懵逼......

*!*    题目如下:
*!*    有九个同学,姑且给他们背后贴上纸条,纸条上编号分别为:A,B,C...I
*!*    让他们站成一个圆圈,由A同学开始,从1开始报数,
*!*    当有同学报"5"时,这个同学退出圈子.
*!*    这个同学之后的一个同学,重新开始从1开始报数,
*!*    当有同学报"5"时,这个同学退出圈子.周而复始...
*!*     ......
*!*    直到剩下最后一个同学.
*!*    问:这个同学,背后纸条上编号为?

*!*    头脑里过一遍,或者纸面上写写画画,或许能找到答案,
*!*    但是我要的不是答案,而是过程,而且把这个过程,用程序语言描述出来.

*!*    程序运行后,希望输出这样的效果:
*!*    第1轮,E同学退出...
*!*    第2轮,A同学退出...
*!*     ...
*!*    第?轮,?同学退出...至此,只剩下最后一位?同学.

*!*    欢迎各位用你们擅长的编程语言来求得答案,并展示过程.
*!*    时间:2021-3-17
    CLEAR
    CLEAR ALL
    SET SAFETY OFF
   
    PUBLIC kz,nRecc,nYs
    CLOSE DATABASES
   
    SELECT * from ys INTO TABLE jgcl
    SELECT * from ys WHERE 1=2 INTO TABLE qhpx
   
    kz=.T.
    DO WHILE kz=.T.
      SELECT jgcl
      GO top
      nRecc=RECCOUNT()
      DO CASE
        CASE nRecc>=5
          GO 5
          COPY TO ls NEXT 1
          COPY TO ls1 FOR RECNO()>5
          COPY TO ls2 FOR RECNO()<5
          SELECT qhpx
          APPEND FROM ls
          SELECT jgcl
          ZAP
          APPEND FROM ls1
          APPEND FROM ls2
         
        CASE nRecc<5
          IF nRecc=1
            kz=.F.
          ELSE
            nYs=MOD(5,nRecc)
            IF nRecc>nYs
              GO nYs
              COPY TO ls NEXT 1
              COPY TO ls1 FOR RECNO()>nYs
              COPY TO ls2 FOR RECNO()<nYs
              SELECT qhpx
              APPEND FROM ls
              SELECT jgcl
              ZAP
              APPEND FROM ls1
              APPEND FROM ls2
            ELSE
              nYs=MOD(nYs,nRecc)
              GO nYs
              COPY TO ls NEXT 1
              COPY TO ls1 FOR RECNO()>nYs
              COPY TO ls2 FOR RECNO()<nYs
              SELECT qhpx
              APPEND FROM ls
              SELECT jgcl
              ZAP
              APPEND FROM ls1
              APPEND FROM ls2
            ENDIF   
          ENDIF
      ENDCASE
    ENDDO
    SELECT qhpx
    GO top
    SCAN
      ? "第"+ALLTRIM(STR(RECNO()))+"位出局的同学是: " + yxrdm
    ENDSCAN
    SELECT jgcl
    ? "最后剩下的同学是:  "+yxrdm
   
    CLOSE DATABASES
    RETURN
   
#12
吹水佬2021-03-18 15:39
以下是引用吹水佬在2021-3-18 10:33:41的发言:

反过来玩又如何,如:
设:有一个乱序的9个同学队列,让他们站成一个圆圈
从第1个同学开始报数,当有同学报"5"时,这个是A同学,出队
这个A同学之后的一个同学,重新开始从1开始报数,当有同学报"5"时,这个是B同学,出队
周而复始.........
直到最后一个是I同学,出队
最后按出队的顺序就是9个同学代号的顺序队列: A B C D E F G H I
求:这个乱序的9个同学队列?

目测:
  x x x x A x x x x
  B x x x A x x x x
  B x x x A x C x x
  B x x D A x C x x
  B x E D A x C x x
  B x E D A F C x x
  B x E D A F C x G
  B H E D A F C x G
  B H E D A F C I G
#13
wengjl2021-03-19 08:22
程序代码:
    CLEAR
    CLEAR ALL
    SET SAFETY OFF
   
    PUBLIC kz,nRecc,nYs     &&& kz-循环的控制,nRecc-加工处理表的记录数,nYs-余数
    CLOSE DATABASES
   
    SELECT * from ys INTO TABLE jgcl    &&& YS.DBF表二个字段(ID,YXRDM)
    SELECT * from ys WHERE 1=2 INTO TABLE qhpx
   
    kz=.T.
    DO WHILE kz=.T.
      SELECT jgcl
      GO top
      nRecc=RECCOUNT()
      DO CASE
        CASE nRecc>=5
          GO 5
          COPY TO ls NEXT 1
          COPY TO ls1 FOR RECNO()>5
          COPY TO ls2 FOR RECNO()<5
          SELECT qhpx
          APPEND FROM ls
          SELECT jgcl
          ZAP
          APPEND FROM ls1
          APPEND FROM ls2
          *--游戏人数5人以上,直接将第5个取出,后队变前队
        CASE nRecc<5
          IF nRecc=1
            kz=.F.
          ELSE
            nYs=MOD(5,nRecc)
            IF nRecc>nYs
              GO nYs
              COPY TO ls NEXT 1
              COPY TO ls1 FOR RECNO()>nYs
              COPY TO ls2 FOR RECNO()<nYs
              SELECT qhpx
              APPEND FROM ls
              SELECT jgcl
              ZAP
              APPEND FROM ls1
              APPEND FROM ls2
            ELSE
              nYs=MOD(nYs,nRecc)
              GO nYs
              COPY TO ls NEXT 1
              COPY TO ls1 FOR RECNO()>nYs
              COPY TO ls2 FOR RECNO()<nYs
              SELECT qhpx
              APPEND FROM ls
              SELECT jgcl
              ZAP
              APPEND FROM ls1
              APPEND FROM ls2
            ENDIF   
          ENDIF
          *--少于5人,需要进行转圈,通过取余数来确定
      ENDCASE
    ENDDO
    SELECT qhpx
    APPEND FROM jgcl
    REPLACE yxrdm WITH CHR(64+RECNO()) all
    SELECT * from qhpx ORDER BY id INTO TABLE ysrand
    SELECT ysrand
    BROWSE
   
    CLOSE DATABASES
    RETURN

还是11楼那个附件里的 YS.DBF 使用。
#14
wengjl2021-03-19 09:22
程序代码:
     ****************
     * 让出圈后的排序符合要求
     ****************
     CLEAR
     SET SAFETY OFF     
     CLOSE DATABASES
     CREATE TABLE ys (id n(2),yxrdm c(1))
     FOR i=1 TO 9
       APPEND BLANK
       REPLACE id WITH i
       REPLACE yxrdm WITH CHR(i+64)
     ENDFOR
     COPY TO ks
     USE ks
     REPLACE yxrdm WITH '' ALL
     CLOSE DATABASES
     *----
     nRecn=1
     SELECT 0
     USE ys
     SELECT 0
     USE ks
     SELECT ys
     SCAN
       sn=0
       SELECT ks
       GO nRecn
       kz=.T.
       DO WHILE kz
         IF EMPTY(ks.yxrdm)
           sn=sn+1
           IF sn=5
             nRecn=RECNO()
             EXIT
           ENDIF
           SKIP 1
           IF EOF()
             GO TOP
           ENDIF
         ELSE
           SKIP 1
           IF EOF()
             GO TOP
           ENDIF   
         ENDIF
       ENDDO
       REPLACE ks.yxrdm WITH ys.yxrdm
       SELECT ys
     ENDSCAN
     SELECT ks
     BROWSE
     RETURN
#15
sdta2021-03-22 09:37
程序代码:
LOCAL la[9]
FOR lnj = 1 TO 9
    la[lnj] = CHR(64 + 9 - lnj + 1)
ENDFOR
lnCnt = 9
? "出局顺序:"
?
DO WHILE lnCnt > 0
    FOR lnj = 1 TO 5
        IF EMPTY(la[9])
            lnj = lnj - 1
        ENDIF
        IF lnj = 5
            ?"第 " + TRANSFORM(9 - lnCnt + 1) + " 轮 同学" + la[9]
            la[9] = ""
        ENDIF
        c1 = la[9]
        AINS(la, 1)
        la[1] = c1
    ENDFOR
    lnCnt = lnCnt - 1
ENDDO
#16
sdta2021-03-28 10:00
针对楼主说的9个人问题,也可以用截取字符的办法完成这个算法,速度还是不错的,有兴趣的朋友可以试着写段代码
1