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

回复 1# 老刘1号

问题1,只有首个元素可以移动,他可以移动到任意位置吗
若按C数组操作,如果你可以移动到中间位置,那不是还等于其他元素也可以移动了
问题2,想看stackoverflow原帖,也许是leetcode上面的题目?

TOP

本帖最后由 523066680 于 2019-1-22 13:13 编辑

int a[5] = {a,b,c,d,e} 把数组变成 {b,c,a,d,e}
b和c 不是从 1,2的位置变成了 0,1的位置吗。(这种允许的话,感觉跟打牌手法的插入排序差不多。)

除非说这是一个定制的数据结构,每个数之间有足够的间隙,开头的数字可以插入任意数字中间而其他数字不需要移动。
比如 a,,,,b,,,,c,,,,d,,,,e,,,,

回复 5# 老刘1号
    不纠结数据结构,纠结的是描述。觉得你现在的描述就比较合理了,其他数字被动移动。

TOP

本帖最后由 523066680 于 2019-1-22 15:13 编辑

有缺陷/未完成,大概方向,unshift 取出首个数字,和剩下的各个元素做减法,找出相差距离最近的数字(分为L和R)的对应坐标,插入。可能做足判断会好一些,待完善。
  1. my @arr = qw/5 1 9 3 2 4 6/;
  2. my ($first, $L,$R,$r_id, $l_id, $dt);
  3. my $max = 100000;
  4. for (1..5)
  5. {
  6.     $first = shift @arr;
  7.     $L = -$max;
  8.     $R = $max;
  9.     $r_id = 0;
  10.     $l_id = 0;
  11.     for $i ( 0 .. $#arr ) {
  12.         $dt = $arr[$i] - $first;
  13.         if ( $dt > 0 && $dt <= $R) { $r_id = $i, $R = $dt; }
  14.         if ( $dt < 0 && $dt >= $L) { $l_id = $i, $L = $dt; }
  15.     }
  16.     if ( $R == $max ) {
  17.         push @arr, $first;
  18.     } else {
  19.         splice( @arr, $r_id, 0, $first );
  20.     }
  21.     #printf "%d - %d: %d, %d: %d\n", $first, $l_id, $L, $r_id, $R;
  22.     print join(",", @arr), "\n";
  23. }
  24. #print join("", @arr);
复制代码
1,9,3,2,4,5,6
9,3,1,2,4,5,6
3,1,2,4,5,6,9
1,2,3,4,5,6,9

特地找一副扑克牌玩了一下,为啥人玩起来就这么自然…… 转成代码总是有纰漏,
纠正了某些情况下不能完全处理的问题,也未经过严格验证,暂时这样。
  1. my @arr = qw/7 3 4 1 10 9 8 11 24/;
  2. my ($first, $L,$R,$r_id, $l_id, $dt);
  3. my $max = 100000;
  4. my $ok = 0;
  5. while (1)
  6. {
  7.     $first = shift @arr;
  8.     $L = -$max;
  9.     $R = $max;
  10.     $r_id = 0;
  11.     $l_id = 0;
  12.     for $i ( 0 .. $#arr ) {
  13.         $dt = $arr[$i] - $first;
  14.         if ( $dt > 0 && $dt <= $R) { $r_id = $i, $R = $dt; }
  15.         if ( $dt < 0 && $dt >= $L) { $l_id = $i, $L = $dt; }
  16.     }
  17.     if ( $L != -$max )
  18.     {
  19.         # 如果有相对较小的数字,优先移至最邻近者
  20.         splice( @arr, $l_id+1, 0, $first );
  21.     } else {
  22.         if ( $R == $max ) {
  23.             # 如果未找到更大的数字,直接堆到最后
  24.             push @arr, $first;
  25.         } else {
  26.             # 判断数组中是否还有 左边大于右边的情况
  27.             $ok = 1;
  28.             for my $i ( 0 .. $#arr-1 ) {
  29.                 if ( $arr[$i] > $arr[$i+1] ) {
  30.                     splice( @arr, $i+1, 0, $first );
  31.                     $ok = 0;
  32.                     last;
  33.                 }
  34.             }
  35.             last if $ok;
  36.         }
  37.     }
  38.     #printf "%d -- [%d]: %d, [%d]: %d\n", $first, $l_id, $L, $r_id, $R;
  39.     print join(",", @arr), "\n";
  40. }
复制代码
  1. 3,4,7,1,10,9,8,11,24
  2. 4,7,1,3,10,9,8,11,24
  3. 7,1,3,4,10,9,8,11,24
  4. 1,3,4,7,10,9,8,11,24
  5. 3,4,7,10,1,9,8,11,24
  6. 4,7,10,1,3,9,8,11,24
  7. 7,10,1,3,4,9,8,11,24
  8. 10,1,3,4,7,9,8,11,24
  9. 1,3,4,7,9,10,8,11,24
  10. 3,4,7,9,10,1,8,11,24
  11. 4,7,9,10,1,3,8,11,24
  12. 7,9,10,1,3,4,8,11,24
  13. 9,10,1,3,4,7,8,11,24
  14. 10,1,3,4,7,8,9,11,24
  15. 1,3,4,7,8,9,10,11,24
复制代码
  1. 2,3,5,1,4
  2. 3,5,1,2,4
  3. 5,1,2,3,4
  4. 1,2,3,4,5
复制代码
1

评分人数

TOP

回复 8# 老刘1号

    已更新

TOP

本帖最后由 523066680 于 2019-1-22 17:32 编辑

试试粗暴一点,递归求不同解、最优解。(逻辑不够完整,怕卡太久,限制了层数 lv <= 5),
  1. my @arr = qw/8 9 1 2 5/;
  2. my @order = ();
  3. our @ways;
  4. solver(0, \@order, @arr);
  5. my $first;
  6. for my $w ( @ways )
  7. {
  8.     printf "Solution: %s\n", join(",", @$w);
  9.     my @brr = @arr;
  10.     for my $mov ( @$w )
  11.     {
  12.         $first = shift @brr;
  13.         splice( @brr, $mov, 0, $first );
  14.         printf "%s\n", join(",", @brr);
  15.     }
  16.     printf "\n";
  17. }
  18. sub solver
  19. {
  20.     my ($lv, $order) = (shift, shift);
  21.     my @arr = @_;
  22.     my @brr;
  23.     my $first;
  24.     my $res;
  25.     return if $lv == 5;
  26.     if (check(\@arr) == -1) {
  27.         #printf "[%d] %s %s\n", $lv, join(",", @arr), join(",", @brr);
  28.         for my $i ( 1 .. $#arr ) {
  29.             @brr = @arr[1..$#arr];
  30.             splice(@brr, $i, 0, $arr[0] );
  31.             $order[$lv] = $i;
  32.             $res = solver( $lv+1, $order, @brr );
  33.             #if ( $res == 1 ) {last;}
  34.         }
  35.         return 1 if $res == 1;
  36.     } else {
  37.         #printf "%s\n", join(",", @arr);
  38.         push @ways, [@{$order}[0..$lv-1] ];
  39.         return 1;
  40.     }
  41. }
  42. sub check
  43. {
  44.     my $ar = shift;
  45.     grep { return -1 if ( $ar->[$_] > $ar->[$_+1] ) } ( 0 .. $#$ar-1);
  46.     return 1;
  47. }
复制代码
  1. Solution: 1,1,4,4
  2. 9,8,1,2,5
  3. 8,9,1,2,5
  4. 9,1,2,5,8
  5. 1,2,5,8,9
  6. Solution: 1,4,3
  7. 9,8,1,2,5
  8. 8,1,2,5,9
  9. 1,2,5,8,9
  10. Solution: 2,4,1,3
  11. 9,1,8,2,5
  12. 1,8,2,5,9
  13. 8,1,2,5,9
  14. 1,2,5,8,9
  15. Solution: 4,1,1,4
  16. 9,1,2,5,8
  17. 1,9,2,5,8
  18. 9,1,2,5,8
  19. 1,2,5,8,9
  20. Solution: 4,4
  21. 9,1,2,5,8
  22. 1,2,5,8,9
  23. [Finished in 0.1s]
复制代码
粗暴中发现那个数组的处理过程可以更短,6次解决:
  1. Move Steps: 5,5,5,2,6,5
  2. 3,4,7,1,10,9,8,11,24 <- Original
  3. 4,7,1,10,9,3,8,11,24
  4. 7,1,10,9,3,4,8,11,24
  5. 1,10,9,3,4,7,8,11,24
  6. 10,9,1,3,4,7,8,11,24
  7. 9,1,3,4,7,8,10,11,24
  8. 1,3,4,7,8,9,10,11,24
复制代码

TOP

本帖最后由 523066680 于 2019-1-22 17:51 编辑

回复 1# 老刘1号

    Tiger就是那个初中一年级,做MIT英文原版数学试卷、精通C++、Python、JAVA,熟练 PyTorch、 Tensorflow、会写CNN DNN RNN KNN,的神奇少年吗。
看到那个群里这么多大神,吓得我退群点了个外卖。

TOP

本帖最后由 523066680 于 2019-1-22 19:01 编辑

回复 14# 老刘1号

你用批处理,在解决问题的时候还要为批处理伤脑筋,很不容易~
要是换成其他脚本,各种骚操作、语法糖用了再说,舒服。

但仔细想想确实很蛋疼的感觉,不想写

TOP

本帖最后由 523066680 于 2019-1-22 21:36 编辑

回复 16# 老刘1号

移动两个元素的同时还要保持其他元素的原有顺序,感觉好蛋疼

犯了一个数组坐标偏移计算错误,花了很多时间去矫正(就是临时数组消减后下标减小了,失算)
  1. my @idx = qw/0 1 2 3 4/;
  2. my ($a, $b) = (3,4);
  3. my $apos = $a;
  4. my $bpos = $b;
  5. my $exchange = 0;
  6. printf "%d %d, %s\n", $apos, $bpos, join(",", @idx);
  7. # 首位数插入idx[$b]的前方
  8. $first = shift @idx;
  9. splice( @idx, $b-1, 0, $first );
  10. $apos-=1;
  11. printf "%d %d, %s\n", $apos, $bpos, join(",", @idx);
  12. while (1)
  13. {
  14.     $first = shift @idx;
  15.     if ( $first == $a ) {
  16.         splice( @idx, $bpos, 0, $first );
  17.         $apos = $bpos;
  18.         $bpos -= 1;
  19.         $exchange = 1;
  20.     } else {
  21.         if ( $bpos ne $a ) {
  22.             if ($exchange) {
  23.                 splice( @idx, $apos-1, 0, $first );
  24.                 $bpos -= 1;
  25.             } else {
  26.                 splice( @idx, $bpos-1, 0, $first );
  27.                 $apos -= 1;
  28.             }
  29.         } else {
  30.             last;
  31.         }
  32.     }
  33.     printf "%d %d, %s\n", $apos, $bpos, join(",", @idx);
  34. }
复制代码
前面两个数是位置变化
  1. 3 4, 0,1,2,3,4
  2. 2 4, 1,2,3,0,4
  3. 1 4, 2,3,0,1,4
  4. 0 4, 3,0,1,2,4
  5. 4 3, 0,1,2,4,3
复制代码
1

评分人数

TOP

本帖最后由 523066680 于 2019-1-22 22:25 编辑

回复 20# search_Sudoku

惊醒梦中人,我竟然没意识到到这个过程同样可以构建一个逐步扩大的有序列表, why didn't I think of that!
这样完全可以获得[步数]在[元素个数]以内的解,无论效率还是实现,应该都是最佳方案。

本来我在想那个递归跑出来的最短步骤解,但是想想就像通常情况下的的排序,某些解同样有更快的步骤,这些步骤的缩减有时只能是针对性的,即使实现了,也会改变效率的“天枰”。

TOP

本帖最后由 523066680 于 2019-1-23 12:47 编辑

回复 24# 老刘1号

我先用递归跑出来一些结果,然后去强行找规律、强行解释一波,发现没什么大的漏洞就拿来用了

有明确的调换方法,假设要调换列标3和7

012345678  -  将7和3位置调换,可以预见的是3和7调换后,012在7的前面(成为7的前缀);456同理;
012345601278  -
将排头的012依次插入7的前方。
0003456012738 -
0127已经达成,现在开头的是数字3,将它放在数字7后面
00004560127
45638 - 然后将前缀456插入数字3的前面。


有了这个规则,就可以来一波语法糖
  1. my @index = qw/0 1 2 3 4 5 6 7 8/;
  2. my ($a, $b) = (3,7);
  3. my ($apos, $bpos) = ($a, $b);
  4. my $show = sub {printf "[%d,%d] %s\n", $apos, $bpos, join(",", @index)};
  5. $show->();
  6. # $a 的前缀转移到 $b 前面
  7. grep { splice( @index, $bpos-1, 0, shift @index ); $apos--; $show->() } (1..$a);
  8. # $a 移到 $b 后面
  9. splice( @index, $bpos, 0, shift @index );
  10. $apos = $bpos, $bpos--;
  11. $show->();
  12. # $b 的前缀转移到 $a 前面
  13. grep { splice( @index, $apos-1, 0, shift @index ); $bpos--; $show->() } ($a+1..$b-1);
  14. exit;
复制代码
  1. [3,7] 0,1,2,3,4,5,6,7,8
  2. [2,7] 1,2,3,4,5,6,0,7,8
  3. [1,7] 2,3,4,5,6,0,1,7,8
  4. [0,7] 3,4,5,6,0,1,2,7,8
  5. [7,6] 4,5,6,0,1,2,7,3,8
  6. [7,5] 5,6,0,1,2,7,4,3,8
  7. [7,4] 6,0,1,2,7,4,5,3,8
  8. [7,3] 0,1,2,7,4,5,6,3,8
复制代码
.
回复 26# search_Sudoku

     针对 3,4,7,1,10,9,8,11,24(24暂时用K替代) 昨晚拿着扑克牌手动排了几次,处理方式和你的描述接近但有差异,
差不多7次。晚点儿再实践实践
    又想了想,递归也可以优化优化(暴力解虽然费时,但是省心 )。

TOP

本帖最后由 523066680 于 2019-1-23 16:33 编辑

回复 22# search_Sudoku

      按这个方式实现了(二分搜索没做进去),很利落
  1. =info
  2.     Ref:
  3.     http://www.bathome.net/redirect.php?goto=findpost&ptid=51910&pid=217048
  4. =cut
  5. my @arr = qw/25 23 4 9 8 2 1 12 15/;
  6. my $offset;
  7. my $first;
  8. printf "%s <- Original\n", join(",", @arr);
  9. # 查找末尾有序数组的起点
  10. $offset = $#arr+1 - seqsizes( \@arr );
  11. while ( $offset > 0 || $arr[0] > $arr[1] )
  12. {
  13.     $first = shift @arr;
  14.     insert( \@arr, $offset, $first );
  15.     $offset--;
  16.     printf "%s\n", join(",", @arr);
  17. }
  18. sub insert
  19. {
  20.     my ($arr, $begin, $ele) = @_;
  21.     for my $i ( $begin .. $#$arr ) {
  22.         if ($arr->[$i] > $ele ) { splice( @$arr, $i, 0, $ele ); return; }
  23.     }
  24.     splice( @$arr, $#$arr+1, 0, $ele );
  25. }
  26. sub seqsizes
  27. {
  28.     my ($r, $size) = (shift, 1);
  29.     for my $i (1..$#$r) {
  30.         $r->[-$i] > $r->[-$i-1] ? $size++ : last;
  31.     }
  32.     return $size;
  33. }
复制代码
  1. 3,4,7,1,10,9,8,11,24 <- Original
  2. 4,7,1,10,9,3,8,11,24
  3. 7,1,10,9,3,4,8,11,24
  4. 1,10,9,3,4,7,8,11,24
  5. 10,9,1,3,4,7,8,11,24
  6. 9,1,3,4,7,8,10,11,24
  7. 1,3,4,7,8,9,10,11,24
复制代码
  1. 25,23,4,9,8,2,1,12,15 <- Original
  2. 23,4,9,8,2,1,12,15,25
  3. 4,9,8,2,1,12,15,23,25
  4. 9,8,2,1,4,12,15,23,25
  5. 8,2,1,4,9,12,15,23,25
  6. 2,1,4,8,9,12,15,23,25
  7. 1,2,4,8,9,12,15,23,25
复制代码

TOP

返回列表