Board logo

标题: 【练习-059】批处理解实现自动新生分班 [打印本页]

作者: batman    时间: 2010-6-27 17:33     标题: 【练习-059】批处理解实现自动新生分班

出题目的:
    让大家熟练掌握随机数概念和用法
解题要求:
    1、代码简洁、高效、通用并不生成临时文件
    2、请版主级会员暂缓解题,但可跟贴为新人做指导
加分规则:
    本题满分15分,视情况加分
题目如下:
    某学校要新招收400名学生,其中有100名优等生、100名高等生、100名中等生、100名差等生,现在学校校长要求将这400名
学生随机安排到新开的10个班,同时要求每个班有10名优等生、10名高等生、10名中等生、10名差等生,并且要在学生报到的时候
就分好班次,并且他要为两个学生开后门,一个是将教育局局长的儿子分到第3班,一个是将文化局局长的女儿分到第8班。这下可
难坏了招生办的老师,一时都不知道怎么办,正好这时教务处长来了,他马上想到一个好办法,终于招生办解决了校长交给的难题,
受到校长的表扬。现在假设你是教务处长,你能想到什么好办法吗?请注意,我不是要你们写文字,要看你们的代码,请最后将每个
班的学生显示出来(最好是分屏显示)
随题提示:
    1、优等生用A-1至A-100表示,高等生用B-1至B-100表示,中等生用C-1至C-100表示,差等生用D-1至D-100表示
    2、教育局局长的儿子用B-60表示,文化局局长的女儿用C-49表示
    3、班级用X-1至X-10表示
    4、假设学生报到的顺序不是随机的,是按A-D、1-100的顺序来进行,即先按1-00的顺序招收优等生,再按1-100的顺序招收高等
生,依此类推直到招收D-100,所以才要求在报到时就随机分好班

要睡觉了,看来本题确实有难度,先给出本人的参考答案吧,不过大家还是争取不要看答案哦:


  1. @echo off&setlocal enabledelayedexpansion
  2. for %%a in (A B C D) do (
  3.     for /l %%b in (1,1,100) do set ".!random!_%%a-%%b=%%a-%%b"
  4.     for /f "tokens=2 delims==" %%b in ('set .') do (
  5.         if not defined code set "code=123456789a"&set /a n=10
  6.         set /a a=!random!%%n
  7.         for %%c in (!a!) do (
  8.             set "a=!code:~%%c,1!"
  9.             for %%c in (!a!) do (
  10.                 set "code=!code:%%c=!"&set "X-%%c=!X-%%c! %%b"&set /a n-=1
  11.                 for %%d in (B-3 C-8) do (
  12.                     for /f "tokens=1,2 delims=-" %%e in ("%%d") do (
  13.                         if %%e equ %%a if %%f equ %%c if not defined _%%e%%f set "_%%e%%f=%%b"
  14.                     )
  15.                 )
  16.                 for %%d in (B-60 C-49) do if "%%d" equ "%%b" set ".%%d=X-%%c"
  17.             )  
  18.         )
  19.     )
  20.     for /f "delims==" %%b in ('set .') do set "%%b="
  21. )
  22. set "X-10=%X-a%"
  23. if "%X-3:B-60=%" equ "%X-3%" set "X-3=!X-3:%_B3%=B-60!"&call,set "!.B-60!=%%!.B-60:B-60=%_B3%!%%"
  24. if "%X-8:C-49=%" equ "%X-8%" set "X-8=!X-8:%_C8%=C-49!"&call,set "!.C-49!=%%!.C-49:C-40=%_C8%!%%"
  25. for /l %%a in (1,1,10) do cls&echo X-%%a班:&echo.&echo !X-%%a:~1!&pause>nul
复制代码

-------------------------------------------------------------------------------------------------------------------------------------------
此代码重复随机,不可取,请大家看后面的代码。

[ 本帖最后由 batman 于 2010-6-29 09:22 编辑 ]
作者: 随风    时间: 2010-6-27 18:29

每个班规定40人吗
那两个开后门的是差等生,还是?
那个所谓的办法,能用文字表达一下吗?
作者: Batcher    时间: 2010-6-27 18:31     标题: 回复 2楼 的帖子

1、是的,因为题目里面说“同时要求每个班有10名优等生、10名高等生、10名中等生、10名差等生”。
2、B代表高等、C代表中等。
作者: batman    时间: 2010-6-27 18:48     标题: 回复 2楼 的帖子

所谓的办法在每个人的心中,呵呵。。。

如觉得有难度,先可不开后门(本来就反对开后门

[ 本帖最后由 batman 于 2010-6-27 20:44 编辑 ]
作者: 随风    时间: 2010-6-27 21:05

应该不难,但要求简洁。。。只怕有难度。
作者: neorobin    时间: 2010-6-27 21:36

  1. @echo off & setlocal enableDelayedExpansion
  2. for %%c in (A B C D) do (
  3.   set "Max=10"
  4.   for /l %%i in (0 1 9) do (set "ptClass%%i=%%i"& set Cnt%%i=0)
  5.   for /l %%s in (1 1 100) do (
  6.     set /a to_pt=!random! %% !Max!
  7.     set /a "to=ptClass!to_pt!"
  8.     for %%t in (!to!) do (
  9.       set "X-%%t=!X-%%t! %%c-%%s"
  10.       set /a Cnt%%t+=1
  11.       if !Cnt%%t! geq 10 (
  12.         set /a last=Max-1
  13.         set /a tt=ptClass!to_pt!
  14.         set /a ptClass!to_pt!=ptClass!last!
  15.         set /a ptClass!last!=tt
  16.         set /a Max-=1
  17.       )
  18.     )
  19.   )
  20. )
  21. set "X-10=!X-0!"& set "X-0="
  22. for /l %%i in (1 1 10) do set "X-%%i=!X-%%i! "& rem 加入尾部空格防止单数错误替换
  23. echo 开后门之前...
  24. set X-
  25. pause
  26. echo 开后门...
  27. call :backDoor B-60 X-3 11
  28. call :backDoor C-49 X-8 21
  29. echo 开后门之后...
  30. set X-
  31. pause
  32. exit /b
  33. :backDoor 学生编号 班编号 班内目标号 C-49 安排到 X-8, C 起始于 #21
  34. for /l %%i in (1 1 10) do (
  35.   if /i "X-%%i" neq "%2" (
  36.     (echo !X-%%i!|find /i "%1">nul)&&(
  37.       for /f "tokens=%3 delims= " %%t in ("!%2!") do (
  38.         (echo 调换: X-%%i 班的 %1 ^<==^> %2 班的 %%t )
  39.         set "X-%%i=!X-%%i:%1 =%%t !" & rem 带尾部空格防止双数被当成单数替换,
  40.         set "%2=!%2:%%t =%1 !"       & rem 例: B-12 会当作 B-1 与 2
  41.       )  
  42.       exit /b
  43.     )
  44.   )
  45. )
  46. exit /b
复制代码

[ 本帖最后由 neorobin 于 2010-6-27 21:38 编辑 ]
作者: 随风    时间: 2010-6-27 21:45

开后门还真是有难度,思考中。。。。。
作者: neorobin    时间: 2010-6-27 21:55     标题: 回复 7楼 的帖子

我的方法是先全部 平等 对待 安排, 之后再找出相应的 班和学生 调换一下(如果已经安排到了所要的班就免调换了)即可,  前部的代码排除了 特殊性, 可以写得简洁
作者: batman    时间: 2010-6-27 21:55

开后门也不难,思路打开点,试试交换法,嘿嘿。。。
作者: neorobin    时间: 2010-6-27 22:07     标题: 回复 9楼 的帖子

对, 不需要调换学生, 找到所在的班, 直接和想要的班换一下就可以了, 实质上也就是把后门学生所要的班号 换成 所要求的就行了, 比如 B-60 被安排到了 8 班, 那么直接把 8 班看成 3  班, 3 班看成 8 班就行了!
作者: batman    时间: 2010-6-27 22:11

开窍了,哈哈,是的,任何问题从多个角度上来想,总能找到解决的好办法的。
作者: neorobin    时间: 2010-6-27 22:33     标题: 再发换班不换学生的

这里换班号的方法是错误的, 13楼, 14楼 有说明
  1. @echo off & setlocal enableDelayedExpansion
  2. for %%c in (A B C D) do (
  3.   set "Max=10"
  4.   for /l %%i in (0 1 9) do (set "ptClass%%i=%%i"& set Cnt%%i=0)
  5.   for /l %%s in (1 1 100) do (
  6.     set /a to_pt=!random! %% !Max!
  7.     set /a "to=ptClass!to_pt!"
  8.     for %%t in (!to!) do (
  9.       set "X-%%t=!X-%%t! %%c-%%s"
  10.       set /a Cnt%%t+=1
  11.       if !Cnt%%t! geq 10 (
  12.         set /a last=Max-1
  13.         set /a tt=ptClass!to_pt!
  14.         set /a ptClass!to_pt!=ptClass!last!
  15.         set /a ptClass!last!=tt
  16.         set /a Max-=1
  17.       )
  18.     )
  19.   )
  20. )
  21. set "X-10=!X-0!"& set "X-0="
  22. for /l %%i in (1 1 10) do set "X-%%i=!X-%%i! "& rem 加入尾部空格防止单数错误替换
  23. echo 开后门之前...
  24. set X-
  25. pause
  26. echo 开后门...
  27. call :backDoor B-60 X-3
  28. call :backDoor C-49 X-8
  29. echo 开后门之后...
  30. set X-
  31. pause
  32. exit /b
  33. :backDoor 学生编号 班编号 [color=red] 错误后门方法 [/color]
  34. for /l %%i in (1 1 10) do (
  35.   if /i "X-%%i" neq "%2" (
  36.     rem find 后是一个含尾空格的查找串 "%1 ", 避免将1位以上的数字错误处理
  37.     (echo !X-%%i!|find /i "%1 ">nul)&&(
  38.       (echo 调换: %1 所在的 X-%%i 班 ^<==^> %2 班)
  39.       set tt=!X-%%i!& set X-%%i=!%2!& set "%2=!tt!"
  40.       exit /b
  41.     )
  42.   )
  43. )
  44. exit /b
复制代码

[ 本帖最后由 neorobin 于 2010-6-27 23:49 编辑 ]
作者: 随风    时间: 2010-6-27 22:50

假设两个后门学生都在一个班呢?
又或者都在3班或8班呢?
作者: neorobin    时间: 2010-6-27 23:44     标题: 回复 13楼 的帖子

正要说这个, 用换班的方法会造成矛盾,
设换班号之前两个后门生其中一个在 M 班, 要去 P 班
而另一个在 N 班, 要去 Q 班
就存在两次班号调换, M<==>P, N<==>Q
这样, 当 M, N, P, Q 这四个数字中有相同, 但又不是 M=Q且P=N的情况, 就会至少使一个后门生到不了要去的班号.

单单调换学生时, 如果学生不属一个类别, 不会有问题, 如果有相同类别的后门生都要换班, 那么代码须要更复杂的设计
  1. @echo off & setlocal enableDelayedExpansion
  2. for %%a in (A B C D) do (
  3.   for /l %%i in (1001 1 1100) do set "sStu=!sStu!%%a-%%i"
  4.   set "sStu=!sStu:-1=-!"&  set "base=100"
  5.   for /l %%x in (1 1 10) do (
  6.     for /l %%i in (1 1 10) do (
  7.       set /a "start=(!random!%%base)*5"
  8.       for %%s in (!start!) do (
  9.         set "choose=!sStu:~%%s,5!"
  10.         for %%c in (!choose!) do (
  11.           set "X-%%x=!X-%%x! %%c"
  12.           set "sStu=!sStu:%%c=!"
  13.           set /a base-=1
  14. ) ) ) ) )
  15. (echo 开后门之前...)&set X-&pause
  16. (echo 开后门...)&call :backDoor B-060 X-3 11&call :backDoor C-049 X-8 21
  17. (echo 开后门之后...)&set X-&pause
  18. exit /b
  19. :backDoor 学生编号 班编号 班内目标号 如: C-049 安排到 X-8, C 起始于 #21
  20. for /l %%i in (1 1 10) do (
  21.   if /i "X-%%i" neq "%2" (
  22.     (echo !X-%%i!|find /i "%1">nul)&&(
  23.       for /f "tokens=%3 delims= " %%t in ("!%2!") do (
  24.         (echo 调换: X-%%i 班的 %1 ^<==^> %2 班的 %%t )
  25.         set "X-%%i=!X-%%i:%1=%%t!"
  26.         set "%2=!%2:%%t=%1!"
  27.       )  
  28.       exit /b
  29. ) ) )
  30. exit /b
复制代码

[ 本帖最后由 neorobin 于 2010-6-28 00:17 编辑 ]
作者: 随风    时间: 2010-6-28 00:25

为了开这个后门,导致代码又长又多作许多无用功,汗,找不到更好的方法,先凑合着用
思路:
先将400名学生分成4组,再乱序,然后在每班每组按顺序取10个,
并同时记录下后门学生所在班级,再记录下3班一名高等生和8班一名差等生
最后把3班的这名高等生编到b60所在班,把b60强行编到3班
8班也是

:
  1. @echo off&setlocal EnableDelayedExpansion
  2. for %%a in (a b c d) do call :loop %%a
  3. for /l %%a in (1 1 10) do (
  4.    set /a t+=1,w+=10
  5.    for %%i in (a b c d) do (
  6.       for /l %%j in (!t! 1 !w!) do (
  7.          set #%%a=!#%%a! !.%%i%%j!
  8.          set tmp=!.%%i%%j!
  9.          if "!.%%i%%j!"=="b60" set j=%%a
  10.          if %%a equ 3 if "!tmp:~0,1!"=="b" if not "!tmp!"=="b60" set t3=!tmp!
  11.          if "!.%%i%%j!"=="c49" set wen=%%a
  12.          if %%a equ 8 if "!tmp:~0,1!"=="c" if not "!tmp!"=="c49" set t8=!tmp!
  13.        )
  14.     )
  15.     set /a t=w
  16. )
  17. echo 两个后门学生原来所在班 !j!  !wen!&echo;
  18. for %%a in (!j!) do set #%%a=!#%%a:b60=! !t3!
  19. for %%a in (!wen!) do set #%%a=!#%%a:c49=! !t8!
  20. set #3=!#3! b60
  21. set #8=!#8! c49
  22. for /l %%a in (1 1 10) do (
  23.    echo %%a班
  24.    echo !#%%a!
  25.    echo;
  26. )
  27. pause&exit
  28. :loop
  29. for /l %%i in (1 1 100) do set .%1%%i=%1%%i
  30. for /l %%i in (1 1 100) do (
  31.     set /a rnd=!random!%%100+1
  32.     for %%j in (!rnd!) do set tmp=!.%1%%j!
  33.     set .%1!rnd!=!.%1%%i!
  34.     set .%1%%i=!tmp!
  35. )
  36. goto :EOF
复制代码

作者: netbenton    时间: 2010-6-28 00:40

排版请在相应的地方改成[Tab]键,就可以行列对齐,好看一点。

先把特殊家伙的给提出来,到适当的时候再放回去~~
加入随机数后,利用了set $排序,得到了随机的结果,
  1. @echo off&setlocal enabledelayedexpansion
  2. for /l %%b in (1,1,100) do (
  3.         set n=!n! %%b
  4. )
  5. for %%a in (A B C D) do (
  6.         set #%%a=!n!
  7.         for /l %%b in (1,1,10) do set _%%a%%b=10
  8. )
  9. set ##B3=B-60&set #B=!#B: 60=!
  10. set ##C8=C-49&set #C=!#C: 49=!
  11. set/a _B3-=1,_C8-=1
  12. for %%a in (A B C D) DO (
  13.         for %%b in (!#%%a!) do set $%%a_!random:~-2!_%%b=1
  14. )
  15. set n=1
  16. for /f "tokens=1,2,3 delims=$_=" %%a in ('set $') do (
  17.         for %%k in (!n!) do (
  18.                 set X%%k=!X%%k!%%a-%%c        
  19.                 set /a _%%a%%k-=1
  20.                 if !_%%a%%k! equ 0 (
  21.                         set/a n=n%%10+1
  22.                         if defined ##%%a!n! call set X!n!=%%X!n!%%%%##%%a!n!%%        
  23.                 )
  24.         )
  25. )
  26. for /l %%a in (1,1,10) do (
  27. echo;第%%a班:
  28. echo !x%%a!
  29. )
  30. pause
复制代码

[ 本帖最后由 netbenton 于 2010-6-28 01:28 编辑 ]
作者: neorobin    时间: 2010-6-28 00:46

我先后给出的代码分别采用了两种思路:

第 1 种. 在每一类学生里, 每 100 个学生逐个排进随机的班号里, 须对班号排满 10 个与否计数判断处理
第 2 种. 在每一类学生里, 每 100 个学生先行编进线性表(字符串实现),
然后, 10 个班依次在表里随机取出 10 个学生,
每取出一个学生后, 随机索引的上限逐次减 1, 线性表中对应的学生编号也删除掉
直到安排好所有 400 名学生进入 全部 10 个班

后门: 找出后门生所在的班, 再与后门生要去的目标班里的同类的第一个学生调换
因为两个后门生, 分属不同的 B 和 C 类, 所以代码上不用考虑两次(最多可能)调换之间的矛盾.
作者: 随风    时间: 2010-6-28 00:57

后门: 找出后门生所在的班, 再与后门生要去的目标班里的同类的第一个学生调换
假设3班的第一个学生是 c49 呢?考虑这个问题没有。
作者: neorobin    时间: 2010-6-28 01:04     标题: 回复 18楼 的帖子

我的解法中 c49 不可能是 3 班的第一个学生, C 类的学生只能是第 21--30 个的范围之内, B 类只会和其他班的 B 类学生调换, 而且不同类别的学生 在一个班内部的编号不可能相同:
A: 1--10
B: 11-20
C: 21-30
D: 31-40
只要题目不要求有多于一个的同类的后门生都要安排, 我的代码不须进一步复杂
作者: sgaizxt001    时间: 2010-6-28 02:20

终于知道如何使用随机来解此题了。哎,看来真得新建个帐号,不然真的没人回答中校的简单问题

[ 本帖最后由 sgaizxt001 于 2010-6-28 08:56 编辑 ]
作者: 随风    时间: 2010-6-28 03:31

本想再写一个,看了16楼 netbenton 代码,感觉无论在效率还是简洁都以无法超越了,放弃。
赞一个。
作者: batman    时间: 2010-6-28 11:21     标题: 救命!!!

下面这段代码很简洁,但不知为什么总是1班不对,其他没什么问题,眼睛看红了脑袋想破了,也没找到原因,大家
都来帮帮忙吧!
  1. @echo off&setlocal enabledelayedexpansion
  2. for %%a in (A B C D) do (
  3.     set /a m=1
  4.     for /l %%b in (1,1,100) do if "%%a-%%b" neq "B-60" if "%%a-%%b" neq "C-49" set "%%a#!random!_%%b=%%a-%%b"
  5.     for /f "tokens=2 delims==" %%b in ('set %%a#') do (
  6.         set /a n+=1
  7.         for %%c in (!m!) do (
  8.             set "X-%%c=!X-%%c! %%b"&set /a v=10
  9.             for %%d in (B3 C8) do if "%%a%%c" equ "%%d" set /a v=9
  10.             if !n! equ !v! set /a n=0,m+=1
  11.         )
  12.     )
  13. )
  14. set "X-3=%X-3% B-60"&set "X-8=%X-8% C-49"
  15. for /l %%a in (1,1,10) do cls&echo X-%%a班:&echo.&echo !X-%%a:~1!&pause>nul
复制代码
思路:
  依次将四组学生(除去后门生)按乱序后平分的方法分到10个班,每组分配到每班的学生是10名(当后门生所在
组遇到3、8班时则只分配9名学生),最后将后门生加到所要到的班次中就是的。在实际上校方制作398个四组十类
标签,其中3班高等生组标签和8班中等生组标签各9个,其余各班各组标签各10个,让学生在报到时按组抽签,最后
将后门生直接安排到要到的班级就可以了。
----------------------------------------------------------------------------------------------------------------------------------------------
哈哈,解决了!晕,原来是错将C8写成了D8,真的是太粗心了。

[ 本帖最后由 batman 于 2010-6-28 11:30 编辑 ]
作者: zqz0012005    时间: 2010-6-28 11:22

这个题倒是让我想起了如何用bat操作数组。本想模拟几个数组处理函数,还没设计好。
  1. @echo off
  2. setlocal enableDelayedExpansion
  3. set num=100
  4. set class_num=10
  5. for %%a in (A B C D) do (
  6. call :getRanArr %%a 1 %num%
  7. set %%a=!%%a:#=%%a!
  8. )
  9. set backdoor1=B60
  10. set backdoor2=C49
  11. set target1=3
  12. set target2=8
  13. set /a cnt = num / class_num
  14. for /l %%a in (1 1 %class_num%) do (
  15. for %%x in (A B C D) do (
  16. for /l %%i in (1 1 %cnt%) do (
  17. for /f %%A in ("!%%x!") do set class_%%a=!class_%%a! %%A& set %%x=!%%x:*%%A =!
  18. )
  19. )
  20. echo class %%a:
  21. echo !class_%%a:~1!
  22. echo;
  23. if /i "!class_%%a:%backdoor1%=!" neq "!class_%%a!" set postion1=%%a
  24. if /i "!class_%%a:%backdoor2%=!" neq "!class_%%a!" set postion2=%%a
  25. )
  26. echo yesterday: %backdoor1%=%postion1%, %backdoor2%=%postion2%
  27. echo;
  28. call :go_backdoor 1 //后来加的
  29. call :go_backdoor 2
  30. echo;
  31. pause
  32. exit /b
  33. :go_backdoor //^_^//
  34. set backdoor=!backdoor%1!
  35. set postion=!postion%1!
  36. set target=!target%1!
  37. set class_%postion%=!class_%postion%:%backdoor%=...!
  38. set class_%target%=!class_%target%! %backdoor%
  39. rem catch a scape-goat
  40. set level=%backdoor:~0,1%
  41. set str=!class_%target%:*%level%=!
  42. for /f %%a in ("!str!") do set scape-goat=%level%%%a
  43. set class_%target%=!class_%target%:%scape-goat% =!
  44. set class_%postion%=!class_%postion%:...=%scape-goat%!
  45. echo new class %postion%:
  46. echo !class_%postion%!
  47. echo new class %target%:
  48. echo !class_%target%!
  49. echo;
  50. goto :eof
  51. :getRanArr arrName start end [step] //不对参数作合法性检查,coder自己保证参数的正确性
  52. setlocal enableDelayedExpansion
  53. set /a "start=%2, end=%3, step=(^!(%40/10))|(%40/10)"
  54. set "_ret="
  55. for /l %%a in (%start% %step% %end%) do set #_!random!_%%a=1
  56. for /f "tokens=2 delims=#_=" %%a in ('set #_') do set _ret=!_ret! #%%a
  57. endlocal & set %1=%_ret:~1%
  58. goto :eof
  59. rem ToDo: find time to implement these function
  60. rem How about letting bat operate array? Crazy or not?
  61. :shuffle arrName len cnt //洗牌
  62. :slice arrName start [end] //返回一个数组的一段(指定起停)
  63. :sliceLen arrName start length //返回一个数组的一段(指定长度)
  64. :splice arrName start deleteCount //从一个数组中移除一个或多个元素,如果必要,在所移除元素的位置上插入新元素,返回所移除的元素
复制代码

作者: zqz0012005    时间: 2010-6-28 11:31

我的思路竟然和随风基本上是一样的!

代码有点啰嗦,最近在学习编程规范。
作者: neorobin    时间: 2010-6-28 15:26     标题: 回复 15楼 的帖子

以下为 cmd 输出重定向到文件的方法 摘取 随风 15 楼代码的一次输出
3班
a72 a13 a8 a95 a25 a91 a29 a37 a92 a54 b25 b70 b3 b55 b32 b47 b28 b52  b99 c50 c72 c40 c100 c57 c54 c95 c96 c38 c42 d97 d34 d57 d92 d22 d63 d61 d16 d37 d24 b99 b60

5班
a52 a36 a75 a70 a99 a68 a33 a50 a84 a24 b35 b100 b7 b46 b23 b14 b69 b16 b59 b40  c37 c69 c76 c29 c93 c94 c23 c67 c70 d42 d20 d80 d49 d53 d7 d21 d54 d75 d81 c27

8班
a90 a15 a9 a74 a39 a7 a57 a23 a78 a67 b8 b31 b48 b68 b37 b27 b97 b80 b34 b20 c5 c7 c75 c26 c56 c82 c98 c62 c13 c27 d84 d27 d3 d98 d64 d30 d82 d87 d74 d26 c49

发现 b 类和 c 类学生总会多出一个, 有可能在同一个班, 也可能在不同的班:
此次输出中, 3 班有 2 个 b99, 而 5 班和 8 班各有一个 c27

用 notepad++ 查找输出文件中的 b 和 c 计数, 总是得到 101 个结果.
作者: 随风    时间: 2010-6-28 17:06     标题: 回复 25楼 的帖子

感谢提醒
确实会这样,原因是只记得替换忘记删除原来的了
代码太垃圾,也懒的改了,汗,为了开个后门,代码比原来长了一倍~~~
作者: 523066680    时间: 2010-6-28 18:00

小弟表示不急, 按以前的感觉是越晚做出来越好。不过越晚就越没人鸟了=。=
作者: batman    时间: 2010-6-28 20:47

不知道你们运行了我22楼的代码不,要说简洁已经相当简洁了,效率也还行(要搞速就需要在乱序上下功夫了,用set *确实有点慢)。

期望大家能想出更好的方法来。
作者: iti50i68j2h0    时间: 2010-6-28 21:14

  1. @echo off & SetLocal EnableDelayedExpansion
  2. set /a n=0,X=1,B_60=0,C_49=0
  3. :loop
  4. for %%a in (A B C D) do (
  5.     if "!_%%a!" neq "1" (
  6.         set /a %%a=!random!%%100+1
  7.         if defined %%a_!%%a! (set repeat=1) else set /a %%a_!%%a!=0,_%%a=1
  8.     )
  9. )
  10. if "%repeat%"=="1" set repeat=0 & goto loop
  11. set "X-%X%=!X-%X%!A-%a% B-%B% C-%C% D-%D% "
  12. set /a n+=1,_A=0,_B=0,_C=0,_D=0,1/(n%%10) 2>nul || set /a X+=1
  13. if %n%==30 set "X-3=!X-3:B-%B%=B-60!" & set "B_%B%="
  14. if %n%==80 set "X-8=!X-8:C-%C%=C-49!" & set "C_%C%="
  15. if %n% lss 100 goto loop
  16. for /l %%a in (1 1 10) do echo X-%%a: & echo !X-%%a! & pause & cls
复制代码
思路:
按班级顺序分配,学生是随机的。
一个班 10 次 goto,每次 goto 生成四个随机数(优等生、高等生、中等生、差等生),如果某个随机数定义过,则重复这次 goto。
原意是 100 次 goto,但不可能没有重复随机数...我计算了下,要 goto 一千次左右...

[ 本帖最后由 iti50i68j2h0 于 2010-6-28 22:04 编辑 ]
作者: neorobin    时间: 2010-6-28 21:37     标题: 再发一个

:: 生成 1--100 的随机数序列, 删除掉 后门生编号, 平分进 10 个班,
:: 但 X-10 班会少分两个学生.
:: 将 3 班的第 1 个 B 类学生剪切给 10 班, 再把 B-060 加入 3 班
:: 将 8 班的第 1 个 C 类学生剪切给 10 班, 再把 C-049 加入 8 班
  1. @echo off&setlocal enableDelayedExpansion&mode con cols=126
  2. for /l %%i in (1001 1 1100) do set "sStu=!sStu!S-%%i"
  3. set "sStu=!sStu:-1=-!"
  4. for %%a in (A B C D) do (
  5.   set sS=!sStu:S=%%a!& set sS=!sS:B-060=!& set "sS=!sS:C-049=!"
  6.   set "UP=100" & if %%a geq B if %%a leq C set "UP=99"
  7.   for /l %%x in (1 1 10) do (for /l %%i in (1 1 10) do (
  8.       if !UP! gtr 0 ( set /a "start=!random!%%UP*5"
  9.         for %%s in (!start!) do (for %%c in (!sS:~%%s^,5!) do (
  10.           set "X-%%x=!X-%%x! %%c"& set "sS=!sS:%%c=!"& set /a UP-=1
  11. ) ) ) ) ) )
  12. echo 开后门之前:&set X-& set "X-10=!X-10!!X-3:~60,6!!X-8:~120,6!"
  13. set X-3=!X-3:~0,60! B-060!X-3:~66!& set "X-8=!X-8:~0,120! C-049!X-8:~126!"
  14. echo 开后门之后:&set X-&pause
复制代码

作者: sgaizxt001    时间: 2010-6-29 05:48

目前只会做没有考虑后门的,而且效率不高。我觉得我的代码是新手最容易看的懂的。就贴出来了。
把x%%a=%%d !x%%a!中间的空格换为tab键。
  1. @echo off
  2. setlocal enabledelayedexpansion
  3. for %%a in (A B C D) do for /l %%b in (1,1,100) do set #%%a-!random!-%%a-%%b=0
  4. for /l %%a in (1,1,10) do (
  5.   for /f "tokens=3,4 delims=-=" %%b in ('set #') do (
  6.    for %%d in (%%b-%%c) do (
  7.     set /a m+=1
  8.     set /a n=m%%10+1
  9.     if !n! equ %%a set x%%a=%%d !x%%a!
  10. )
  11. )
  12. )
  13. for /l %%j in (1,1,10) do (
  14.   echo 第%%j班:
  15.   echo !x%%j!
  16. )
  17. pause
复制代码

[ 本帖最后由 sgaizxt001 于 2010-6-29 06:20 编辑 ]
作者: 523066680    时间: 2010-6-29 08:55

=。=  这两人编码靠后,干涉较多额。 我还是老老实实做简单的那个吧
goto 惯了
  1. @echo off
  2. setlocal enabledelayedexpansion
  3. set spec=#ABCD
  4. set /a m=1
  5. :main
  6. for /l %%a in (1,1,100) do (set i_%%a=%%a)
  7. set /a lp=1,range=100
  8. :lp
  9.     set /a tmpx=%random% %% range + 1
  10.     set /a class=!i_%tmpx%! %% 10 + 1
  11.     set class_%class%=!class_%class%! !spec:~%m%,1!%lp%
  12.     set /a i_%tmpx%=i_%range%
  13. if %lp% lss 100 (set /a lp+=1,range-=1 &goto :lp)
  14. if %m% lss 4 (set /a m+=1 &goto :main)
  15. for /l %%i in (1,1,10) do (echo class %%i = !class_%%i!)
  16. pause
复制代码


Yoshi, 重新了解了一下情况,果断放弃.=。=

[ 本帖最后由 523066680 于 2010-6-29 09:40 编辑 ]
作者: neorobin    时间: 2010-6-29 16:50     标题: 嘿嘿, 这次的 word 字数统计比 batman 22楼的少

  1. @echo off&setlocal enabledelayedexpansion
  2. for %%t in (A B C D) do (
  3.         for /l %%i in (1001 1 1100) do set "#%%t!random:~-2!%%i=%%i"
  4.         for /f "tokens=2 delims==" %%n in ('set #%%t') do set "U=!U!%%t-%%n "
  5.         set U=!U:-1=-!
  6.         set "U=!U:B-060 =!      "& set "U=!U:C-049 =!      "
  7.         for /l %%s in (0 60 540) do ( set /a V=%%s/60+1
  8.                 for %%c in (x-!V!) do set "%%c=!%%c!!U:~%%s,60!"
  9.         )
  10.         set "U="
  11. )
  12. set "X-10=!X-10:      =!!X-3:~60,6!!X-8:~120,6!"
  13. set X-3=!X-3:~0,60!B-060 !X-3:~66!& set "X-8=!X-8:~0,120!C-049 !X-8:~126!"
  14. set X&pause
复制代码
这次 100 个学生表的次序 采用了 set 输出排序, set 输出一系列变量是会按变量名的次序来排列的, 但事先安排 100 个变量名仅前部相同, 变量值却是 1--100 中的任意一个, 且没有变量值相同的情况, 而且 1--100 每个值都是安排到了一个随机生成的变量名的变量, 再用 set 输出, 输出的变量名是按正常次序来的, 但变量的值却成了无规则的乱序了, 部分示例如下:
#A0074=74
#A0134=34
#A0270=70
#A0352=52
#A0381=81
#A0497=97
#A0550=50
#A0553=53
#A063=3
#A0658=58

作者: neorobin    时间: 2010-6-29 19:23

才发现我 33 楼的乱序方法居然是和 batman 22 楼一样的, 有巧合但也有特色: 做完代码才发现 33 楼居然没有用一个 if.

batman 好像认为 set 排乱序不太好, 我可真想不到还有什么更简洁的方式.
作者: terse    时间: 2010-7-2 10:27

  1. @echo off&setlocal enabledelayedexpansion
  2. for /l %%i in (1001,1,1100) do set s=%%i&set var=!var!#!s:~-3!
  3.     for %%i in (A B C D) do (
  4.         set %%i=!var!&set _%%i=100
  5.         for /l %%j in (1 1 10) do set %%i.%%j=10
  6.   )
  7. set B.2=9&set C.8=9&set _B=99&set _C=99
  8. set X3= B-60&set X8= C-49&set B=!B:#060=!&set C=!C:#049=!
  9. for %%a in (A B C D) do (
  10.     for /l %%i in (1 1 10) do (
  11.     for /l %%j in (1 1 !%%a.%%i!) do (
  12.     set /a n=!random!%%_%%a*4
  13.     for %%b in ("!n!") do for %%c in ("!%%a:~%%~b,4!") do (
  14.     for /f "tokens=* delims=#0" %%d in (%%c) do (
  15.         set %%a=!%%a:%%~c=!
  16.         set /a _%%a-=1
  17.         set x%%i=!x%%i! %%a-%%d
  18. )))))
  19. for /l %%i in (1,1,10) do echo %%i班:&echo!x%%i!
  20. pause
复制代码

作者: zqz0012005    时间: 2010-7-3 12:53

  1. @echo off
  2. setlocal enableDelayedExpansion
  3. set amount=100
  4. set types=A B C D
  5. set slices=10
  6. set special=B-60-3 C-49-8
  7. for /l %%a in (1 1 %amount%) do set arr=!arr! #-%%a
  8. for %%i in (%types%) do (
  9.     set "%%i=!arr:#=%%i! " 后面特意加了空格
  10.     set /a amount_%%i=amount
  11.     for /l %%a in (1 1 %slices%) do set /a num_%%i_%%a = amount / slices
  12. )
  13. for %%a in (%special%) do (
  14.     for /f "tokens=1,2,3 delims=-" %%i in ("%%a") do (
  15.         set %%i=!%%i: %%i-%%j = !
  16.         set /a amount_%%i -= 1
  17.         set /a num_%%i_%%k -= 1
  18.     )
  19. )
  20. for %%i in (%types%) do (
  21.     set #=!%%i!
  22.     set /a left = amount_%%i
  23.     for /l %%a in (1 1 %slices%) do (
  24.         for /l %%n in (1 1 !num_%%i_%%a!) do (
  25.             set /a ran = !random! %% left + 1
  26.             set $=!#!
  27.             for /l %%x in (1 1 !ran!) do set $=!$:* =!
  28.             for /f %%x in ("!$!") do set item=%%x
  29.             set slices_%%a=!slices_%%a! !item!
  30.             for %%x in (!item!) do set #=!#: %%x = !
  31.             set /a left -= 1
  32.         )
  33.     )
  34. )
  35. for %%a in (%special%) do (
  36.     for /f "tokens=1,2,3 delims=-" %%i in ("%%a") do set slices_%%k=!slices_%%k! %%i-%%j
  37. )
  38. for /l %%a in (1 1 %slices%) do echo class %%a:& echo !slices_%%a!& echo;
  39. echo;
  40. pause
  41. exit /b
  42. :shuffle arrName len cnt //洗牌
复制代码
适应每个数组元素名字未知(开始生成一个数组是当没有给出时手动生成)、长度不定(当然总长度必须小于单个变量最大长度8k)
作者: neorobin    时间: 2010-7-3 15:56     标题: 回复 36楼 的帖子

听你说正在学习编程规范, 一点好奇: 难道你不是计算机专业的(当然你可以不答我)
你这帖的代码, 我没大细看, 但 发现 echo off 和 setlocal 没用 & 放在同一行了,
set /a 后面的运算符也都前后都空出一个空格了.
这点上我提一个题外话, 至少我在做一些代码时自己犯了一个狭念:
把代码做浮华性的 "简化", 甚时在变量名上做不必要的简化, 略到只用一个字母.

什么样的代码才是好的? 正确, 高效, 易读, 而所谓 "简洁", 应是代码具备了实质上内在的品质而自然表现出的外在品质.
作者: zqz0012005    时间: 2010-7-3 17:06

为什么大家都觉得我是计算机专业的呢?

编程规范要求一行上最好只放一条语句(其实大家都懂的)

set /a 后面加空格是可以的而且是应该的,以突出运算逻辑和提高可读性。它和set进行字符串赋值有所不同,对于后者多余的空格也会成为变量名/值的一部分。

变量命名应该尽量做到短小而又有所含义(能做到见名知义就更好了),不要全用毫无意义的a、b、c之类的,当然有一些习惯性用法,比如n表示数量,i用于for循环变量等。

语句对齐问题:我发现做到并坚持这一原则的人真的很少。批处理就算再简单,基本的结构还是有的,不要一味为了简洁就无视它。
复合语句收尾的括号应与关键字在同一列上对齐(主要就是if、for,因为开始的括号不能另起一行放在行首,否则就与它对齐了),内部子语句应该适量缩进(一般4个空格,多数编辑器都是这个默认值,不用你多敲)。当子语句只有一两个且较简单,也可以省去括号(在bat中不反对大家这么做)。

正确、高效、易读,最容易做到的就是易读,却往往最难被人做到,悲乎哀哉!就算代码功能上不怎么样,变量名称、基本意思、流程结构应该写清楚呀,起码能让人看得懂。(terse的代码一向高效,但我一般都没怎么看过,感觉太“难看”了^_^)
作者: sgaizxt001    时间: 2010-7-3 22:04

易读这点有待商量,因为你们写的好多代码对于我们这类初学者来说,看起来头疼
作者: Batcher    时间: 2010-7-3 23:08

赞同,至少要有缩进。
每次看到全部顶格的代码,总有一种想打人的冲动。
作者: zqz0012005    时间: 2010-7-4 00:41     标题: 回复 39楼 的帖子

看36楼的代码,你觉得哪里头疼呢?

代码功能和技巧原理可能不大懂,需要相当的基础和积累才行。但代码格式、基本结构应该容易看懂吧(少数风格迥异的牛人除外,只看三两遍和没看一样)
比如一行句子是什么结构、怎么断句、主体命令是什么,for循环是哪一种、循环体里面有哪些子句,if语句的条件分支是怎样的,从哪里到哪里、是什么逻辑关系;总之大体框架应该读能出来。

试比较35楼的
set /a n=!random!%%_%%a*4
和36楼的
set /a ran = !random! %% left + 1

新手对上面那句,可能很难明白(当然结合代码是必须的,可是对新手还是很难);但下面那句就不一样了(当然本身就简单一点)
作者: sgaizxt001    时间: 2010-7-4 08:24

看的就是技巧啦,为什么你写的出来,我写不出来。为什么你的代码效率高而我的慢的要死。为什么你的代码那么短而且不生成临时文件,而我就不行。就是看你们的代码去找出这些问题,学习你们的思路和技巧
就拿一个不生成临时文件的方法来说:set
在我开始学批处理,看教程的时候,我对于set的关注和主观想法认为他的作用是设置变量,忽略了他的另一个功能显示变量。所以在做练习题的时候,我就搞不懂为什么可以这样用。寒夜孤星教过我,然后慢慢掌握了这个用法
在拿这个题来说,刚开始我不知道怎么着手,当时我的想法是如何取10个不同的随机数来取出这些数,我看了一下随风的代码发现了set #%%a-!random!-%%a-%%b=0的巧妙用法,然后一下困扰我的难题就解开了,同时也做出了这个题,虽然效率不高。但是也做出来了
作者: zqz0012005    时间: 2010-7-4 10:14

那就不是易读性的问题,而是技巧性的问题。
我说过,需要相当的基础和积累才行。

set的这个用法你不会,说明你的基本功还不够,对常用命令都不熟。
set /?
    SET P
会显示所有以字母 P 打头的变量

而set /a进行数学运算时,“您可以使用环境变量值做计算而不用键入那些 % 符号来得到它们的值”
据此分析set /a n=!random!%%_%%a*4
断句一下就是set /a n = !random! %% _%%a * 4
前面的%%是求余运算符(在bat中要写成两个,预处理机制,原理和理论知识),!random!加了!符号,因为它是一个特殊的变量,不是我们手动定义的,而是系统提供的动态环境变量,所以要使用!!来得到其值。而_%%a就是的!_%%a!省去!的形式,只是这个展开过程稍微多一步:先由for展开%%a的值,与_拼接后整个成为一个变量名,再由set得到该变量对应的值。




欢迎光临 批处理之家 (http://bbs.bathome.net/) Powered by Discuz! 7.2