免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: sunzhiguolu
打印 上一主题 下一主题

小学一年级数学题 - 系列-3 [复制链接]

论坛徽章:
0
11 [报告]
发表于 2017-06-25 08:41 |只看该作者
首先说我的答案,有八种。下面说说我的思路,大家看对不对。

第一步:九宫格的中心必须是5。因为中间的数字的两边与对角必须是四对加起来和一致的数。只有取5才能有四对。

到处为止,问题转化成了,四对数加起来等于十的排列组合有多少种?很容易知道是四对数,19,28,37,46

第二步:分析四个角的位置。我分析结论是四个角必须是偶数。因为边之和必须是15,三个数之和是奇数,则必定是俩偶一奇。假定一个角的数是奇数,那么它的对角必定是奇数。同时边的另外两个数就必须得是偶数。也就是边上除了这俩奇数,其他位置必须是偶数。就得有六个偶数,但我们只有四个偶数,所以不可能。

结论一,这时候我们知道四条边中心都是奇数,它们的不同排列组合就是一层运算情况。那么现在来分析下偶数位置会变么?

答案是不会。因为在偶数对中,28,46拆分配对的对所有情况只有两种,一种是24,68。一种是26,48。这两种情况的四个和分别是6,8,12,14。分别对应了四个奇数需要的值。所以每个奇数两边的偶数是固定。并且两个不相对的俩奇数必定需要同样的一个偶数。比如,1需要的组合是68里面有6,7需要的组合是26里面有6。其他情况一样。

所以,问题最终就转化成了转化成了,1、3、5、7四个奇数在四条边中心的位置组合,且要分离相对。

代码表示的话就是,把四条边线中心位,表示位数组的四个索引0,1,2,3。19和37在数组中的位置交叉即可。

很容易看出有8种:1397、1793、9317、9713、3179、3971、7139、7931

奇数组合出来后,偶数排列组合就不说了。找出俩奇数的共同偶数放夹角即可。

纯分析手打,就不上代码了(说不定代码我也不会写

论坛徽章:
0
12 [报告]
发表于 2017-06-25 08:51 |只看该作者
田小江 发表于 2017-06-25 08:41
首先说我的答案,有八种。&#19 ...

最后我想补充的就是,分析完后,用最优的或者你会的数据结构和算法。把各种组合算出来即可。

论坛徽章:
307
程序设计版块每周发帖之星
日期:2016-04-08 00:41:33操作系统版块每日发帖之星
日期:2015-09-02 06:20:00每日论坛发贴之星
日期:2015-09-02 06:20:00程序设计版块每日发帖之星
日期:2015-09-04 06:20:00每日论坛发贴之星
日期:2015-09-04 06:20:00每周论坛发贴之星
日期:2015-09-06 22:22:00程序设计版块每日发帖之星
日期:2015-09-09 06:20:00程序设计版块每日发帖之星
日期:2015-09-19 06:20:00程序设计版块每日发帖之星
日期:2015-09-20 06:20:00每日论坛发贴之星
日期:2015-09-20 06:20:00程序设计版块每日发帖之星
日期:2015-09-22 06:20:00程序设计版块每日发帖之星
日期:2015-09-24 06:20:00
13 [报告]
发表于 2017-06-25 15:24 |只看该作者
本帖最后由 sunzhiguolu 于 2017-06-25 15:29 编辑

回复 11# 田小江
首先一点 非常感谢您的精彩分析。将本来一团乱麻的思路 变得清晰了起来。
就是不知道 如果将心中所想落实到代码会是怎样。(按照您的分析,代码一定非常精彩)

论坛徽章:
12
子鼠
日期:2014-10-11 16:46:482016科比退役纪念章
日期:2018-03-16 10:24:0515-16赛季CBA联赛之山东
日期:2017-11-10 14:32:142016科比退役纪念章
日期:2017-09-02 15:42:4715-16赛季CBA联赛之佛山
日期:2017-08-28 17:11:5515-16赛季CBA联赛之浙江
日期:2017-08-24 16:55:1715-16赛季CBA联赛之青岛
日期:2017-08-17 19:55:2415-16赛季CBA联赛之天津
日期:2017-06-29 10:34:4315-16赛季CBA联赛之四川
日期:2017-05-16 16:38:55黑曼巴
日期:2016-07-19 15:03:112015亚冠之萨济拖拉机
日期:2015-05-22 11:38:5315-16赛季CBA联赛之北京
日期:2019-08-13 17:30:53
14 [报告]
发表于 2017-06-25 23:19 |只看该作者
本帖最后由 523066680 于 2017-06-25 23:20 编辑
  1. =info
  2.     Code by 523066680
  3.     2017-06
  4.     排列元素的方案参考自 http://stackoverflow.com/questions/9122315/permutations-using-perl
  5. =cut

  6. use List::Util qw/sum/;

  7. our @a = (1..9);

  8. #分组,校验的下标顺序
  9. our @chk =
  10.     (
  11.         [1,2,3], [4,5,6], [7,8,9],
  12.         [1,4,7], [2,5,8], [3,6,9],
  13.         [1,5,9], [3,5,7],
  14.     );

  15. #纯属冗余操作(为了前面直观)。统一 -1
  16. grep { $_ = [map { $_-1 } @$_] } @chk;  #全体 -1

  17. #开始迭代
  18. for ( &permute( @a ) )
  19. {
  20.     if (check($_) == 1)
  21.     {
  22.         print join(",", @{$_}[0,1,2]),"\n";
  23.         print join(",", @{$_}[3,4,5]),"\n";
  24.         print join(",", @{$_}[6,7,8]),"\n\n";
  25.     }
  26. }

  27. sub permute
  28. {
  29.     return ([]) unless (@_);
  30.     return map
  31.     {
  32.         my @cdr = @_;
  33.         my $car = splice @cdr, $_, 1;
  34.         map { [$car, @$_] } &permute(@cdr);
  35.     } 0 .. $#_;
  36. }

  37. sub check
  38. {
  39.     my $a_ref = shift;
  40.     my $result = 1;

  41.     for my $ref (@chk)
  42.     {
  43.         if ( sum( map { $a_ref->[$_] } @$ref ) != 15 )
  44.         {
  45.             $result = 0;
  46.             last;
  47.         }

  48.     }
  49.     return $result;
  50. }
复制代码


2,7,6
9,5,1
4,3,8

2,9,4
7,5,3
6,1,8

4,3,8
9,5,1
2,7,6

4,9,2
3,5,7
8,1,6

6,1,8
7,5,3
2,9,4

6,7,2
1,5,9
8,3,4

8,1,6
3,5,7
4,9,2

8,3,4
1,5,9
6,7,2

[Finished in 7.2s]

优化肯定是有的优化的,只是想看看暴力跑法。(我的strawberry perl 安装  Algorithm:ermute 失败了,所以先借用一下别人写好的排列方案)

论坛徽章:
7
戌狗
日期:2013-12-15 20:43:38技术图书徽章
日期:2014-03-05 01:33:12技术图书徽章
日期:2014-03-15 20:31:17未羊
日期:2014-03-25 23:48:20丑牛
日期:2014-04-07 22:37:44巳蛇
日期:2014-04-11 21:58:0915-16赛季CBA联赛之青岛
日期:2016-03-17 20:36:13
15 [报告]
发表于 2017-06-26 00:43 |只看该作者
回复 9# jason680

穷举法 再优化 改良...
填入[0,1]立即检查[0] + [1] > 5 , [2] = 15 -( [0] + [1] )
3 Q ~~

论坛徽章:
7
戌狗
日期:2013-12-15 20:43:38技术图书徽章
日期:2014-03-05 01:33:12技术图书徽章
日期:2014-03-15 20:31:17未羊
日期:2014-03-25 23:48:20丑牛
日期:2014-04-07 22:37:44巳蛇
日期:2014-04-11 21:58:0915-16赛季CBA联赛之青岛
日期:2016-03-17 20:36:13
16 [报告]
发表于 2017-06-26 00:51 |只看该作者
回复 14# 523066680

[Finished in 7.2s]
good machine ~~
wode:
real        0m22.694s
user        0m22.413s
sys        0m0.167s



论坛徽章:
7
戌狗
日期:2013-12-15 20:43:38技术图书徽章
日期:2014-03-05 01:33:12技术图书徽章
日期:2014-03-15 20:31:17未羊
日期:2014-03-25 23:48:20丑牛
日期:2014-04-07 22:37:44巳蛇
日期:2014-04-11 21:58:0915-16赛季CBA联赛之青岛
日期:2016-03-17 20:36:13
17 [报告]
发表于 2017-06-26 01:00 |只看该作者
本帖最后由 rubyish 于 2017-06-25 21:03 编辑

回复 11# 田小江

下面说说我的思路

3Q ~ zhege youyisi. XXle.
  1. #!/usr/bin/perl
  2. # (v5.26.0)
  3. use 5.010;

  4. make();

  5. # _____________________SUB____________________

  6. sub make {
  7.     my @abcd = ( 2, 4, 6, 8 );

  8.     for my $a (@abcd) {
  9.         my $b = 10 - $a;
  10.         my @cd = grep { $_ != $a and $_ != $b } @abcd;
  11.         for my $cd ( [@cd], [ reverse @cd ] ) {
  12.             my ( $c, $d ) = @$cd;
  13.             my @X = ( 15 - $a - $c, 15 - $a - $d, 15 - $c - $b, 15 - $d - $b );

  14.             # a  X0 c
  15.             # X1 5  X2
  16.             # d  X3 b

  17.             say join ' ', $a, $X[0], $c;
  18.             say join ' ', $X[1], 5, $X[2];
  19.             say join ' ', $d, $X[3], $b;
  20.             say '------';
  21.         }
  22.     }
  23. }

  24. __DATA__
  25. $_
复制代码




论坛徽章:
307
程序设计版块每周发帖之星
日期:2016-04-08 00:41:33操作系统版块每日发帖之星
日期:2015-09-02 06:20:00每日论坛发贴之星
日期:2015-09-02 06:20:00程序设计版块每日发帖之星
日期:2015-09-04 06:20:00每日论坛发贴之星
日期:2015-09-04 06:20:00每周论坛发贴之星
日期:2015-09-06 22:22:00程序设计版块每日发帖之星
日期:2015-09-09 06:20:00程序设计版块每日发帖之星
日期:2015-09-19 06:20:00程序设计版块每日发帖之星
日期:2015-09-20 06:20:00每日论坛发贴之星
日期:2015-09-20 06:20:00程序设计版块每日发帖之星
日期:2015-09-22 06:20:00程序设计版块每日发帖之星
日期:2015-09-24 06:20:00
18 [报告]
发表于 2017-06-28 19:38 |只看该作者
回复 7# rubyish
大神知道你厉害,有个地方不是很懂。
如果代码 添加了 use warnings; 该怎样改动一下?

论坛徽章:
307
程序设计版块每周发帖之星
日期:2016-04-08 00:41:33操作系统版块每日发帖之星
日期:2015-09-02 06:20:00每日论坛发贴之星
日期:2015-09-02 06:20:00程序设计版块每日发帖之星
日期:2015-09-04 06:20:00每日论坛发贴之星
日期:2015-09-04 06:20:00每周论坛发贴之星
日期:2015-09-06 22:22:00程序设计版块每日发帖之星
日期:2015-09-09 06:20:00程序设计版块每日发帖之星
日期:2015-09-19 06:20:00程序设计版块每日发帖之星
日期:2015-09-20 06:20:00每日论坛发贴之星
日期:2015-09-20 06:20:00程序设计版块每日发帖之星
日期:2015-09-22 06:20:00程序设计版块每日发帖之星
日期:2015-09-24 06:20:00
19 [报告]
发表于 2017-06-28 19:56 |只看该作者
另外, 7楼代码 利用递归的方式求解 我不是很理解。
不知哪位大神 有时间帮忙 解释一下,最好详细一点。
如果能让我从中有所受益 本人愿出 (1000 积分作为回报, 视情形可提高积分比重 另外再加 +5000 积分作为感谢)

论坛徽章:
12
子鼠
日期:2014-10-11 16:46:482016科比退役纪念章
日期:2018-03-16 10:24:0515-16赛季CBA联赛之山东
日期:2017-11-10 14:32:142016科比退役纪念章
日期:2017-09-02 15:42:4715-16赛季CBA联赛之佛山
日期:2017-08-28 17:11:5515-16赛季CBA联赛之浙江
日期:2017-08-24 16:55:1715-16赛季CBA联赛之青岛
日期:2017-08-17 19:55:2415-16赛季CBA联赛之天津
日期:2017-06-29 10:34:4315-16赛季CBA联赛之四川
日期:2017-05-16 16:38:55黑曼巴
日期:2016-07-19 15:03:112015亚冠之萨济拖拉机
日期:2015-05-22 11:38:5315-16赛季CBA联赛之北京
日期:2019-08-13 17:30:53
20 [报告]
发表于 2017-06-28 20:32 |只看该作者
本帖最后由 523066680 于 2017-06-28 22:10 编辑

回复 19# sunzhiguolu

这个递归写的非常精简,我以前也用类似的方案写排列,不过代码比较长。
将 E_ 函数单独提取出来,把 “语法糖” 之类的东西采用更明确的方式去书写,思路就看得清楚了。
为了方便把元素 1到9 改成了a,b,c。

my @elements = qw/a b c/;
my @container = ();

#传入数组引用,左边是可选元素,右边是容器
func( \@elements, \@container );

sub func
{
    #引用分别传递到 $a,$b
    my ( $a, $b ) = (shift, shift);
    my $last = $#$a;

    #如果 @$a 的元素已经清空,打印 @$b 的内容
    print join(",", @{$b}), "\n" if ( $last < 0 );
   
    #遍历选取 @$a 的元素
    for my $idx ( 0 .. $last )
    {
        #从 @$a 副本取出元素,添加到 @$b,进入下一层选取
        func( [ @$a[0 .. $idx-1, $idx+1 .. $last] ], [ @$b, $a->[$idx] ] );
    }
}

输出:

a,b,c
a,c,b
b,a,c
b,c,a
c,a,b
c,b,a

这个过程可以参考高中的排列组合/概率知识,
第一层,先从 [a,b,c] 中选1个,假设是选 b
第二层,从 剩下的 [a,c] 中选取1个,假设是 a
第三层,从 剩下的 [c] 中选取1个,即 c
最后得到 b,a,c

第一层有3个选项,第二层有2个选项,最后一层1个,共有 3x2x1 种排列顺序。

然后是校验的部分,

    if    ( @$b == 3 ) { sum( @$b[ 0, 1, 2 ] ) != 15 and return }
    elsif ( @$b == 6 ) { sum( @$b[ 3, 4, 5 ] ) != 15 and return }
    elsif ( @$b == 7 ) { sum( @$b[ 0, 3, 6 ] ) != 15
                       || sum( @$b[ 2, 4, 6 ] ) != 15 and return }
    elsif ( @$b == 8 ) { sum( @$b[ 1, 4, 7 ] ) != 15 and return }
    elsif ( @$b == 9 ) { sum( @$b[ 0, 4, 8 ] ) != 15 and return;
        print "@$b[0,1,2]\n@$b[3,4,5]\n@$b[6,7,8]\n";
        print "-----\n";
    }

多个层次的判断可以减少大量冗余的排列过程,例如第一个判断:
当容器数组达到3个元素,可以计算第一行是否和为15,不是的话可以提前退回,节省后面6个元素的排列过程。
后面的判断与此类似。
最后当容器数组的元素达到9个,且最后斜线合计也为15,对符合要求的排列顺序进行输出。

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP