[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
返回列表 发帖

【练习-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的号码
***共同提高***

  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
复制代码

TOP

好题!.思考一下.!!

TOP

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"
复制代码

TOP

忘了将自己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
复制代码
天的白色影子

TOP

回复 19# qzwqzw


    刚重新看了下自己的代码,确实出现这个低级错误,原因是在前面我已将str变量截取了一位,在后面不记得又截取了一位,所以将8888归到了第二类,现已改正。。。
***共同提高***

TOP

回复 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
1

评分人数

    • batman: 按规定给一半的分数PB + 10

TOP

修正了一下
主要是未考虑逆序顺子问题
现在筛选结果基本上与batman的代码一致了
五类数的统计数如下
1,32,488,1691,7788
batman的代码把8888归为了二类
天的白色影子

TOP

回复 17# neorobin
是的,题意本来如此,只怪顶楼举例用了1212 2121 1221这样特殊的数值误导了兄弟,对不起了。。。
***共同提高***

TOP

回复 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 没有特定关系

TOP

回复 15# qzwqzw

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

TOP

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
天的白色影子

TOP

本帖最后由 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

TOP

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

顺子其实也没什么难的
就目前的需要还用不到判断+1和-1
直接罗列出二/三类中所有的顺子组合
然后一次findstr即可
天的白色影子

TOP

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

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

TOP

返回列表