Board logo

标题: 【练习-068】批处理号码筛选练习 [打印本页]

作者: batman    时间: 2012-2-29 10:07     标题: 【练习-068】批处理号码筛选练习

本帖最后由 batman 于 2012-2-29 10:25 编辑

出题目的:
  强化新手对字符截取和if判断的理解
加分原则:
  满分20分,其中解题思路7分,思路描述3分,代码运行效率4分,代码简洁4分,书写规范2分,
  本帖内同一id累计加分不超过40分(请大家在加分时注意)
  如管理层和技术组解题分值减半
  跟帖讨论的视情况加分,最高不超过10分
相关要求:
  请新手自觉独立解题不得抄袭别人代码(可以借鉴)
  请测试代码成功后再发帖
  请最好附上思路说明
题目如下:
  编写批处理代码对所有4位号码进行筛选归类,归类原则如下:
    一类 8888
    二类 x888 aaaa abcd
    三类 xx88 xaaa xabc aabb abab
    四类 xxx8 xxaa abba
    五类 其余的号码
    其中
      x表示不等于其后一位数值的任意数值
                 aaaa为除8888以外的4连号如0000 xaaa xxaa以此类推
      abc abcd代表顺子如123 321 1234 4321
      aabb为形如1122的号码 abab为形如1212的号码 abba为形如1221的号码
作者: jinzeyu    时间: 2012-2-29 10:12     标题: 穷举法 挨个试..

本帖最后由 jinzeyu 于 2012-2-29 11:25 编辑
  1. @echo off&setlocal enableDelayedExpansion&set str=0123456789876543210&set "ml=是三类&goto:eof"&for /l %%i in (1000,1,9999) do call:main %%i
  2. :main
  3. set i=%1
  4. set i1=%i:~0,1%
  5. set i2=%i:~1,1%
  6. set i3=%i:~2,1%
  7. set i4=%i:~3,1%
  8. if "%i%"=="8888" echo %1%ml:三=一%
  9. if "%i:~1%"=="888" echo %1%ml:三=二%
  10. if "%i:~2%"=="88" echo %1%ml%
  11. if "%i:~3%"=="8" echo %1%ml:三=四%
  12. if "%i:~2% %i2%"=="%i:~0,2% %i3%" echo %1%ml:三=二%
  13. if "%i:~1,2%"=="%i:~3%%i:~3%" echo %1%ml%
  14. if "%i:~3%"=="%i3%" echo %1%ml:三=四%
  15. for /l %%j in (0,1,16) do (
  16. if "%1"=="!str:~%%j,4!" echo %1%ml:三=二%
  17. if "%i:~1%"=="!str:~%%j,3!" echo %1%ml%
  18. if "%i:~0,3%"=="!str:~%%j,3!" echo %1%ml%)
  19. if "%i1%%i2%"=="%i4%%i3%" if not "%i1%"=="%i2%" echo %1%ml:一=四%
  20. if "%i1%%i3%"=="%i2%%i4%" if not "%i2%"=="%i4%" echo %1%ml%
  21. if "%i:~0,2%"=="%i:~2%" if not "%i1%"=="%i2%" echo %1%ml%
  22. echo %1是五类
复制代码

作者: jinzeyu    时间: 2012-2-29 10:16

有几个问题:
  如7378算四类吗
  如1331算四类吗
  如1313算三类吗
  如1133算三类吗
作者: batman    时间: 2012-2-29 10:22

回复 3# jinzeyu


    是的,顶楼应该描述得很清楚吧。。。
作者: jinzeyu    时间: 2012-2-29 10:25

回复 4# batman


    哦 我还以为也是连续数字呢
作者: QIAOXINGXING    时间: 2012-2-29 14:10

利用for的嵌套,写出指定特征形式的数字,再排除不正确的。。。。。
思路不清晰,排除得我快累死了。。。。。还不知道对不对。。。。。。。
以后再也不做这种题了。。。。。。。。。
  1. @echo off&SetLocal EnableDelayEdexpansion&cd /d "%~dp0"
  2. if exist "第四类" goto :1
  3. set "num1=0123456789"
  4. set "num2=9876543210"
  5. (for /l %%a in (0 1 9) do (
  6.   if "%%a" leq "5" echo !num1:~%%a,4! & echo !num2:~%%a,4!
  7.   if not "%%a"=="8" (
  8.     echo %%a%%a%%a%%a
  9.     echo %%a888
  10.   )
  11. ))>第二类
  12. (for /l %%a in (0 1 9) do (
  13.   for /l %%b in (0 1 9) do (
  14.     if not "%%b"=="8" (echo %%a%%b88)
  15.     if not "%%b"=="%%a" (
  16.       if not "%%b"=="8"  echo %%a%%b%%b%%b
  17.       set /a "n=%%a-1"
  18.       call set "n1=%%num1:~!n!,1%%"
  19.       call set "n2=%%num2:~!n!,1%%"
  20.       if %%a leq 6 if not "%%b"=="!n1!" if not "%%b"=="!num1:~%%a,1!"  echo  %%
  21. b!num1:~%%a,3!
  22.       if %%a leq 6 if not "%%b"=="!n2!" if not "%%b"=="!num2:~%%a,1!"  echo  %%
  23. b!num2:~%%a,3!
  24.       echo %%a%%a%%b%%b
  25.       echo %%a%%b%%a%%b
  26.     )
  27.   )
  28. ))>第三类
  29. (for /l %%a in (0 1 9) do (
  30.   for /l %%b in (0 1 9) do (
  31.     if not "%%b"=="%%a"  echo %%a%%b%%b%%a
  32.     for /l %%c in (0 1 9) do (
  33.       if not "%%a"=="%%b" if not "%%b"=="%%c"  if not "%%c"=="8" (
  34.          if not "%%b%%c"=="67"  echo  %%a%%b%%c8
  35.          echo %%a%%b%%c%%c
  36.       )
  37.     )
  38.   )
  39. ))>第四类
  40. :1
  41. set /p "number=input:"
  42. if "!number!"=="8888" echo 第一类 & goto :1
  43. findstr  /m  "!number!"   第三类 第二类 第四类 || echo 第五类
  44. echo -------------------------------------------------
  45. goto :1
复制代码

作者: batman    时间: 2012-2-29 15:19

回复 6# QIAOXINGXING


    兄弟是不是想复杂了,这个思路应该很好理的。。。
作者: QIAOXINGXING    时间: 2012-2-29 16:09

回复 7# batman

估计是,,,,,,,坐等答案公布。。。。。。
作者: jinzeyu    时间: 2012-3-4 11:14

不知道有没有简洁的代码 我的太复杂了...一堆if
作者: terse    时间: 2012-3-4 23:11

4个 FOR 循环 省了字符截取 一味的 IF IF
作者: batman    时间: 2012-3-27 09:32

本帖最后由 batman 于 2012-3-29 09:05 编辑

参考答案
  1. @echo off&setlocal enabledelayedexpansion
  2. (for /l %%a in (10000,1,19999) do (
  3.   set "str=%%a"&set "str=!str:~1!"&set "flag=五类"
  4.   set /a a=!str:~,1!,b=!str:~1,1!,c=!str:~2,1!,d=!str:~-1!,b1=b+1,b2=b-1,c1=c+2,c2=c-2,d1=d+3,d2=d-3
  5.   if "!d!" equ "8" set "flag=四类"
  6.   if "!c!" equ "!d!" set "flag=四类"
  7.   if "!a!!b!" equ "!d!!c!" set "flag=四类"
  8.   if "!c!!d!" equ "88" set "flag=三类"
  9.   for %%a in (!b!) do if "!str:%%a=!" equ "!a!" set "flag=三类"
  10.   if "!a!!b!" equ "!c!!d!" set "flag=三类"
  11.   if "!a!!c!" equ "!b!!d!" set "flag=三类"
  12.   for %%a in (1 2) do if "!b%%a!!c%%a!!d%%a!" equ "!b%%a!!b%%a!!b%%a!" set "flag=三类"
  13.   if "!b!!c!!d!" equ "888" set "flag=二类"
  14.   for %%a in (!a!) do if "!str:%%a=!" equ "" set "flag=二类"
  15.   for %%a in (1 2) do if "!a!!b%%a!!c%%a!!d%%a!" equ "!a!!a!!a!!a!" set "flag=二类"
  16.   if "!str!" equ "8888" set "flag=一类"
  17.   echo !flag! !str!
  18. ))>list.txt
  19. start list.txt
复制代码

作者: batman    时间: 2012-3-27 09:56

本帖最后由 batman 于 2012-3-27 10:07 编辑

在此对本题进行一下说明:
  其实本题真的不难,主要还在于判断的技巧性。总的来说有两种筛选的方法,一种是由低级向高级的筛选法,
我们就叫做正向筛选法吧(如11楼)。对任一个四位数我们先将它暂定为五类(set "flag=五类"),然后逐步
判断它是不是符合四、三、二、一类的标准,如果符合标准,flag变量就被重新赋值,最后输出flag的值(?类)
。另一种方法就是由高级向低级的筛选,我们就叫做反向筛选法。对任一个四位数我们先判断它是不是一类,如果
是就标识为一类号码,否则继续判断是不是二类,如果是就标识为二类号码,否则继续以此类推向下判断,最后将
数字标识为它属于的类别。
  这两种筛选方法各有千秋,总体上来说正向筛选法效率较差但代码相对会简单些,就是一行一行的if语句写下
来,而反向筛选法效率较高但代码会相对复杂点,因为其中涉及到数层的if嵌套。
  另外说下筛选中的难点(正反向一样),个人认为最难的就是abcd和abc顺子的判断,但是只要你抓住了这
类号码的特点,也不是很难的事。因为无论是正顺还是反顺,几个数值间肯定是一个以1或-1为差的等差数列,
所以我们只要将后面的数值依次减上其与第一个数值a的差,然后判断生成的新数值是不是一个aaaa 或aaa就可
以了。
作者: qzwqzw    时间: 2012-3-28 13:03

回复 12# batman
从五至一的筛选可以用set
从一至五的筛选可以用findstr
感觉效率不会差别太大
当然没有实测也不敢确定

顺子其实也没什么难的
就目前的需要还用不到判断+1和-1
直接罗列出二/三类中所有的顺子组合
然后一次findstr即可
作者: neorobin    时间: 2012-3-28 16:46

本帖最后由 neorobin 于 2012-3-28 17:09 编辑

借鉴 batman 的差值技巧:
  1. @echo off & setlocal enabledelayedexpansion
  2. > digit.txt (for /l %%i in (10000 1 19999) do (
  3.     (set s=%%i)& set /a w=!s:~1,1!,x=!s:~2,1!,y=!s:~3,1!,z=!s:~4,1!,w-=z,x-=z,y-=z,t=5
  4.     if !s:~-4!==8888 (set "t=1"
  5.     ) else if !s:~-3!==888 (set "t=2"
  6.     ) else for %%s in (000 -3-2-1 321) do if !w!!x!!y!==%%s set "t=2"
  7.     if !t!==5 if !s:~-2!==88 (set t=3) else for %%s in (00 21 -2-1) do if !x!!y!==%%s set "t=3"
  8.     if !t!==5 for %%s in (110 -1-10 101 -10-1) do if !w!!x!!y!==%%s set "t=3"
  9.     if !t!==5 if !s:~-1!==8 (set t=4) else if !y!==0 (set t=4) else (
  10.       for %%s in (011 0-1-1) do if !w!!x!!y!==%%s set t=4)
  11.     echo !t! !s:~-4!
  12. ) )
  13. start "" digit.txt
复制代码
差值基准字符取最后一个字符, 该字符没必要在匹配比较式中出现
0000 ~ 9999 共 10000 个序列:
1 类: 1
2 类: 32
3 类: 351
4 类: 1698
5 类: 7918
作者: qzwqzw    时间: 2012-3-28 18:45

rem 对x的位置严格限定后得到的结果,与楼上的不同,没仔细看谁有问题
rem class1: 1
rem class2: 26          不包含8x88 88x8 888x
rem class3: 424     不包含88xx aaax abcx以及其它x变化位置的模式
rem class4: 1700    不包含8xxx aaxx xaax以及其它xx变化位置的模式
rem class5: 7868
作者: neorobin    时间: 2012-3-28 19:32

回复 15# qzwqzw

按顶楼题意, x(以及 a,b,c,d) 取值并不排除 8 这个数字, 只是在特定位置特定数量连续的 8 的形式, 优先匹配 8 相关的形式.
比较下面几个序列, 可以看到部分问题:
序列      类别       形式
8876        3        xabc
8877        3        aabb
8899        3        aabb
作者: neorobin    时间: 2012-3-28 20:31

回复 11# batman
代码结果的差别(comp 比较) 共有 10 处(并不止这些):

        neorobin    batman
0022    4  xxaa     3  aabb
0033    4  xxaa     3  aabb
0044    4  xxaa     3  aabb
0055    4  xxaa     3  aabb
0066    4  xxaa     3  aabb
0077    4  xxaa     3  aabb
0099    4  xxaa     3  aabb

0202    5           3  abab
0220        5           4  abba
0303    5           3  abab

可见, 对于 a b 的关系, 我全部是按 a b 相差 1 处理的, 而 batman 应该只是在 c 也出现时按相差 1 处理的, 没有 c 出现时, a b 没有特定关系
作者: batman    时间: 2012-3-28 20:43

回复 17# neorobin
是的,题意本来如此,只怪顶楼举例用了1212 2121 1221这样特殊的数值误导了兄弟,对不起了。。。
作者: qzwqzw    时间: 2012-3-28 22:40

修正了一下
主要是未考虑逆序顺子问题
现在筛选结果基本上与batman的代码一致了
五类数的统计数如下
1,32,488,1691,7788
batman的代码把8888归为了二类
作者: neorobin    时间: 2012-3-29 01:16

回复 18# batman

按这种定义改了下:
  1. @echo off & setlocal enabledelayedexpansion
  2. > digit.txt (for /l %%i in (10000 1 19999) do (
  3.     (set s=%%i)& set /a "w=!s:~1,1!,x=!s:~2,1!,y=!s:~3,1!,z=!s:~4,1!,w-=z,x-=z,y-=z,t=5"
  4.     if %%i==18888 (set t=1) else if !x!!y!!z!==008 (set "t=2"
  5.     ) else for %%s in (000 -3-2-1 321) do if !w!!x!!y!==%%s set "t=2"
  6.     if !t!==5 if !y!!z!==08 (set t=3) else for %%s in (00 21 -2-1) do if !x!!y!==%%s set "t=3"
  7.     if !t!==5 (set /a "ab3=^!(w-x|y)|^!(w-y|x)") & if !ab3!==1 (set "t=3"
  8.     ) else if !z!==8 (set t=4) else if !y!==0 (set t=4) else (set /a "ab4=w|x-y") & if !ab4!==0 set "t=4"
  9.     echo !t! !s:~-4!
  10. ) )
  11. start digit.txt
复制代码
得到 5 类总数分别为: 1,32,488,1691,7788
作者: batman    时间: 2012-3-29 09:08

回复 19# qzwqzw


    刚重新看了下自己的代码,确实出现这个低级错误,原因是在前面我已将str变量截取了一位,在后面不记得又截取了一位,所以将8888归到了第二类,现已改正。。。
作者: qzwqzw    时间: 2012-4-6 21:22

忘了将自己findstr的方案贴出来了
效率应该比楼上的代码好一点
  1. @echo off
  2. setlocal EnableDelayedExpansion
  3. (for /l %%i in (10000,1,19999) do set v=%%i&echo !v:~1!)>arr.tmp
  4. set class1=8888
  5. (echo %class1%)>class1.txt
  6. findstr /v "%class1%" < arr.tmp > arr2.tmp
  7. set class2=.888
  8. set class2=%class2% 0123 1234 2345 3456 4567 5678 6789
  9. set class2=%class2% 9876 8765 7654 6543 5432 4321 3210
  10. set class2=%class2% 0000 1111 2222 3333 4444 5555 6666 7777 9999
  11. findstr "%class2%" < arr2.tmp > class2.txt
  12. findstr /v "%class2%" < arr2.tmp > arr3.tmp
  13. set class3-1=..88
  14. set class3-1=%class3-1% .000 .111 .222 .333 .444 .555 .666 .777 .999
  15. set class3-1=%class3-1% .012 .123 .234 .345 .456 .567 .678 .789
  16. set class3-1=%class3-1% .210 .321 .432 .543 .654 .765 .876 .987
  17. findstr "%class3-1%" < arr3.tmp > class3-1.tmp
  18. set class3-2a=00.. 11.. 22.. 33.. 44.. 55.. 66.. 77.. 88.. 99..
  19. set class3-2b=..00 ..11 ..22 ..33 ..44 ..55 ..66 ..77 ..99
  20. findstr "%class3-2a%" < arr3.tmp | findstr "%class3-2b%" > class3-2.tmp
  21. set class3-3a=0.0. 1.1. 2.2. 3.3. 4.4. 5.5. 6.6. 7.7. 8.8. 9.9.
  22. set class3-3b=.0.0 .1.1 .2.2 .3.3 .4.4 .5.5 .6.6 .7.7 .8.8 .9.9
  23. findstr "%class3-3a%" < arr3.tmp | findstr "%class3-3b%" > class3-3.tmp
  24. copy /b class3-?.tmp class3.txt >nul
  25. findstr /v /g:class3.txt < arr3.tmp > arr4.tmp
  26. set class4-1=...8
  27. set class4-1=%class4-1% ..00 ..11 ..22 ..33 ..44 ..55 ..66 ..77 ..99
  28. findstr "%class4-1%" < arr4.tmp > class4-1.tmp
  29. set class4-2a=.00. .11. .22. .33. .44. .55. .66. .77. .88. .99.
  30. set class4-2b=0..0 1..1 2..2 3..3 4..4 5..5 6..6 7..7 9..9
  31. findstr "%class4-2a%" < arr4.tmp | findstr "%class4-2b%" > class4-2.tmp
  32. copy /b class4-?.tmp class4.txt >nul
  33. findstr /v /g:class4.txt < arr4.tmp > class5.txt
  34. del *.tmp
复制代码

作者: terse    时间: 2012-4-10 23:55

IF的效率不给力
练手哦
  1. @echo off&setlocal enableDelayedExpansion
  2. (
  3. for /l %%i in (0 1 9) do (
  4.     for /l %%j in (0 1 9) do (
  5.         for /l %%k in (0 1 9) do (
  6.             for /l %%l in (0 1 9) do (
  7.                 if %%i%%j neq %%k%%l (
  8.                    if %%k neq %%l (
  9.                       if %%j%%i neq %%k%%l (
  10.                          set /a "Ni=%%j^~-%%k|%%k^~-%%l,N=%%i^~-%%j|Ni"
  11.                          if !N! equ 0 (set str=二)else (
  12.                             if !Ni! equ 0  (set str=三)else (
  13.                                 set /a "Ni=~-%%j^%%k|~-%%k^%%l,N=~-%%i^%%j|Ni"
  14.                                 if !N! equ 0 (set str=二)else (
  15.                                    if !Ni! equ 0 (set str=三)else (
  16.                                       if %%l neq 8 (set str=五)else set str=四
  17.                                    )
  18.                                 )
  19.                             )
  20.                          )
  21.                       ) else set str=四
  22.                    ) else if %%j neq %%k (
  23.                           if %%k%%l neq 88 (
  24.                              if %%i equ %%j (set str=三)else set str=四
  25.                           ) else set str=三
  26.                           ) else if %%l neq 8 (set str=三)else set str=二
  27.                 )else if %%j neq %%k (set str=三)else if %%k neq 8 (set str=二)else set str=一
  28.                 echo !STR! %%i%%j%%k%%l
  29. ))))
  30. )>~TEM.tX
  31. start notepad "~TEM.tX"
复制代码

作者: jains521    时间: 2012-10-16 17:18

好题!.思考一下.!!
作者: jains521    时间: 2012-10-17 00:06

  1. @echo off
  2. setlocal enabledelayedexpansion
  3. ::一类 8888
  4. ::二类 x888 aaaa abcd 补充:888x
  5. ::三类 xx88 xaaa xabc aabb abab 补充:88xx, aaax
  6. ::四类 xxx8 xxaa abba  补充: 8xxx, aaxx
  7. ::五类 其余的号码
  8. :: 思路.
  9. :: 好吧这思路很乱.自己也写乱了.
  10. ::整体的思路是利用set /a 用数除0  然后判断各类的特点分类.
  11. set a_b=123456789
  12. set c_b=987654
  13. set b_a=543210
  14. ::连续的思路是利用set /a,替换字符将其他字符乘以0, 如%%i=123 ,  set /a "1/(!a_b:%%i=1*0*1!)"
  15. ::思路是可以用的..不过没有时间处理了..有时间的朋友帮我补充完整吧.
  16. for /l %%i in (9999, -1, 1) do (
  17. set /a "1 / ( %%i - 8888 )"  2>nul && (
  18. set /a "1/(%%i%%1000-888), 1/(%%i/10-888), 1/(%%i%%1111)" 2>nul && (
  19. set /a "a=%%i/1000, b=%%i%%1000/100, c=%%i%%100/10, d=%%i%%10"
  20. set /a "1/(%%i%%100-88), 1/(%%i/100-88),1/((%%i%%1000)%%111), 1/(%%i/100-%%i%%100), 1/((a-b)|(c-d))" 2>nul && (
  21. set /a "1/(%%i%%10-8), 1/(%%i/1000-8), 1/((%%i%%100)%%11), 1/(a*10+b-(d*10+c))" 2>nul&&(
  22. set /a ClassFive+=1!第五类!
  23. )|| (set /a ClassFour+=1!第四类! )
  24. ) || (set /a ClassThree+=1 & set _ClassThree=%%i !_ClassThree!!第三类!)
  25. ) || (if %%i gtr 1000 set /a ClassTwo+=1 & set _ClassTwo=%%i !_ClassTwo!!第二类!)
  26. ) || (set /a ClassOne+=1 & set _ClassOne=%%i !_ClassOne!!第一类!)
  27. )
  28. echo ClassOne=%ClassOne%, ClassTwo=%ClassTwo%, ClassThree=%ClassThree%, ClassFour=%ClassFour%, ClassFive=%ClassFive%
  29. pause>nul
  30. goto :eof
复制代码





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