免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2816 | 回复: 1
打印 上一主题 下一主题

一年多前写的天平称球问题解法 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2011-02-11 22:06 |只看该作者 |倒序浏览
本帖最后由 黑色阳光_cu 于 2011-02-11 22:46 编辑

有12球其大小、形状都一样,其中有一个球重量不一样(不知是轻或重)。给你一把天平,用三次把这个重量不一样的球称(找)出来。

推而广之,有N个球的情况呢?怎么样用Perl解题呢?

这里给出我一年多前写的代码:
  1. #!/bin/env perl

  2. use strict;
  3. use warnings;
  4. # use Data::Dumper;

  5. my @balls = &ball_init(12);
  6. my $bad_ball = &ball_find(\@balls);
  7. if (defined $bad_ball)
  8. {
  9.         &ball_success($bad_ball);
  10. }
  11. else
  12. {
  13.         &ball_fail();
  14. }

  15. <STDIN>;

  16. ########################################################################

  17. sub ball_init
  18. {
  19.         my ($num) = @_;
  20.         my @balls;
  21.         my ($heavy, $error) = (10, 1);

  22.         for (my $n = 1; $n <= $num; $n++)
  23.         {
  24.                 push(@balls, [$n, $heavy]);
  25.         }

  26.         my $select = int(rand($num));
  27.         my $plus_or_minus = int(rand(2));
  28.         if ($plus_or_minus)
  29.         {
  30.                 $balls[$select]->[1] += $error;
  31.         }
  32.         else
  33.         {
  34.                 $balls[$select]->[1] -= $error;
  35.         }

  36.         return @balls;
  37. }

  38. sub ball_find
  39. {
  40.         my @balls = @{$_[0]};
  41.         my ($ref_buf, $deep) = ($_[1], $_[2]);
  42.         $ref_buf = [] if (not defined $ref_buf);
  43.         $deep = 0 if (not defined $deep);
  44.         my (@left, @right, @others);

  45.         ++$deep;
  46.         print "\nA 第$deep次:\n";
  47.         my $length = int(scalar(@balls) / 3 + 0.5);
  48.         $length = 1 if ($length == 0);
  49.         @left = @balls[0 .. $length - 1];
  50.         @right = @balls[$length .. $length * 2 - 1];
  51.         @others = @balls[$length * 2 .. $#balls];
  52.         if (scalar(@balls) < 3)
  53.         {
  54.                 return undef if ($#{$ref_buf} == -1);
  55.                 my $ball = shift(@$ref_buf);
  56.                 print "取回:", &ball_show([$ball]), "\n";
  57.                 my $ball2 = shift(@right);
  58.                 @right = ($ball);
  59.                 print "左边:", &ball_show(\@left), "\n";
  60.                 print "右边:", &ball_show(\@right), "\n";
  61.                 if (&ball_total_heavy(\@left) == &ball_total_heavy(\@right))
  62.                 {
  63.                         return $ball2;
  64.                 }
  65.                 else
  66.                 {
  67.                         return shift(@left);
  68.                 }
  69.         }

  70.         print "左边:", &ball_show(\@left), "\n";
  71.         print "右边:", &ball_show(\@right), "\n";
  72.         print "余下:", &ball_show(\@others), "\n";
  73.         my $heavy_left = &ball_total_heavy(\@left);
  74.         my $heavy_right = &ball_total_heavy(\@right);
  75.         if ($heavy_left == $heavy_right)
  76.         {
  77.                 push(@$ref_buf, @left);
  78.                 push(@$ref_buf, @right);
  79.                 &ball_find(\@others, $ref_buf, $deep);
  80.         }
  81.         else
  82.         {
  83.                 push(@$ref_buf, @others);
  84.                 if ($heavy_left < $heavy_right)
  85.                 {
  86.                         &ball_find2(\@left, \@right, $ref_buf, $deep);
  87.                 }
  88.                 else
  89.                 {
  90.                         &ball_find2(\@right, \@left, $ref_buf, $deep);
  91.                 }
  92.         }
  93. }

  94. sub ball_find2
  95. {
  96.         my @balls = @{$_[0]};
  97.         my @balls2 = @{$_[1]};
  98.         my ($ref_buf, $deep) = ($_[2], $_[3]);
  99.         $ref_buf = [] if (not defined $ref_buf);
  100.         $deep = 0 if (not defined $deep);
  101.         my (@left, @right, @others);

  102.         ++$deep;
  103.         print "\nB 第$deep次:\n";
  104.         my $length = int((scalar(@balls) + scalar(@balls2)) / 3 + 0.5);
  105.         if ((scalar(@balls) == 1 and scalar(@balls2) <= 2) or (scalar(@balls2) == 1 and scalar(@balls) <= 2))
  106.         {
  107.                 my $swp = 0;
  108.                 if (scalar(@balls) != 1)
  109.                 {
  110.                         $swp = 1;
  111.                         my @tmp = @balls;
  112.                         @balls = @balls2;
  113.                         @balls2 = @tmp;
  114.                 }

  115.                 if (@balls2 == 2)
  116.                 {
  117.                         push(@left, shift(@balls2));
  118.                         push(@right, shift(@balls2));
  119.                 }
  120.                 else
  121.                 {
  122.                         if ($#{$ref_buf} == -1)
  123.                         {
  124.                                 return undef;
  125.                         }

  126.                         my $ball = shift(@$ref_buf);
  127.                         print "取回:", &ball_show([$ball]), "\n";
  128.                         push(@left, $ball);
  129.                         push(@right, shift(@balls2));
  130.                 }

  131.                 print "左边:", &ball_show(\@left), "\n";
  132.                 print "右边:", &ball_show(\@right), "\n";
  133.                 my $heavy_left = &ball_total_heavy(\@left);
  134.                 my $heavy_right = &ball_total_heavy(\@right);
  135.                 if ($heavy_left == $heavy_right)
  136.                 {
  137.                         return shift(@balls);
  138.                 }
  139.                 elsif ($swp xor $heavy_left < $heavy_right)
  140.                 {
  141.                         return shift(@right);
  142.                 }
  143.                 else
  144.                 {
  145.                         return shift(@left);
  146.                 }
  147.         }
  148.         else
  149.         {
  150.                 my (@a1, @a2, @a3, @b1, @b2, @b3);
  151.                 my $n = int(scalar(@balls) / 2);
  152.                 @a1 = @balls[0 .. $n - 1];
  153.                 @a2 = @balls[$n .. $n * 2- 1];
  154.                 @a3 = @balls[$n * 2 .. $#balls] if ($n * 2 <= $#balls);
  155.                 my $n2 = $length - $n;
  156.                 if ($n2 > 0)
  157.                 {
  158.                         @b1 = @balls2[0 .. $n2 - 1];
  159.                         @b2 = @balls2[$n2 .. $n2 * 2 - 1];
  160.                         @b3 = @balls2[$n2 * 2 .. $#balls2] if ($n2 * 2 <= $#balls2);
  161.                 }
  162.                 else
  163.                 {
  164.                         @b3 = @balls2;
  165.                 }

  166.                 @left = (@a1, @b1);
  167.                 @right = (@a2, @b2);
  168.                 @others = (@a3, @b3);

  169.                 print "左边:", &ball_show(\@left), "\n";
  170.                 print "右边:", &ball_show(\@right), "\n";
  171.                 print "余下:", &ball_show(\@others), "\n";
  172.                 my $heavy_left = &ball_total_heavy(\@left);
  173.                 my $heavy_right = &ball_total_heavy(\@right);
  174.                 if ($heavy_left == $heavy_right)
  175.                 {
  176.                         push(@$ref_buf, @left);
  177.                         push(@$ref_buf, @right);
  178.                         if (scalar(@a3) == 0 or scalar(@b3) == 0)
  179.                         {
  180.                                 my $heavy_flag = scalar(@a3) == 0 ? 1 : 0;
  181.                                 &ball_find3(\@others, $heavy_flag, $ref_buf, $deep);
  182.                         }
  183.                         else
  184.                         {
  185.                                 &ball_find2(\@a3, \@b3, $ref_buf, $deep);
  186.                         }
  187.                 }
  188.                 elsif ($heavy_left < $heavy_right)
  189.                 {
  190.                         push(@$ref_buf, @right);
  191.                         push(@$ref_buf, @others);
  192.                         if (scalar(@a1) == 0 or scalar(@b2) == 0)
  193.                         {
  194.                                 my $heavy_flag = scalar(@a1) == 0 ? 1 : 0;
  195.                                 &ball_find3([@a1, @b2], $heavy_flag, $ref_buf, $deep);
  196.                         }
  197.                         else
  198.                         {
  199.                                 &ball_find2(\@a1, \@b2, $ref_buf, $deep);
  200.                         }
  201.                 }
  202.                 else
  203.                 {
  204.                         push(@$ref_buf, @left);
  205.                         push(@$ref_buf, @others);
  206.                         if (scalar(@a2) == 0 or scalar(@b1) == 0)
  207.                         {
  208.                                 my $heavy_flag = scalar(@a2) == 0 ? 1 : 0;
  209.                                 &ball_find3([@a2, @b1], $heavy_flag, $ref_buf, $deep);
  210.                         }
  211.                         else
  212.                         {
  213.                                 &ball_find2(\@a2, \@b1, $ref_buf, $deep);
  214.                         }
  215.                 }
  216.         }
  217. }

  218. sub ball_find3
  219. {
  220.         my @balls = @{$_[0]};
  221.         my ($heavy_flag, $ref_buf, $deep) = ($_[1], $_[2], $_[3]);
  222.         $ref_buf = [] if (not defined $ref_buf);
  223.         $deep = 0 if (not defined $deep);
  224.         my (@left, @right, @others);

  225.         return shift(@balls) if (scalar(@balls) == 1);

  226.         ++$deep;
  227.         print "\nC 第$deep次:\n";
  228.         my $length = int(scalar(@balls) / 2);
  229.         @left = @balls[0 .. $length - 1];
  230.         @right = @balls[$length .. $length * 2 - 1];
  231.         print "左边:", &ball_show(\@left), "\n";
  232.         print "右边:", &ball_show(\@right), "\n";
  233.         if ($length * 2 <= $#balls)
  234.         {
  235.                 @others = @balls[$length * 2 .. $#balls];
  236.                 print "余下:", &ball_show(\@others), "\n";
  237.         }

  238.         my $heavy_left = &ball_total_heavy(\@left);
  239.         my $heavy_right = &ball_total_heavy(\@right);
  240.         if ($heavy_left == $heavy_right)
  241.         {
  242.                 return shift(@others) if (scalar(@others) == 1);
  243.                 push(@$ref_buf, @left);
  244.                 push(@$ref_buf, @right);
  245.                 &ball_find3(\@others, $heavy_flag, $ref_buf, $deep);
  246.         }
  247.         else
  248.         {
  249.                 my @balls;
  250.                 if ($heavy_flag xor $heavy_left < $heavy_right)
  251.                 {
  252.                         return shift(@left) if (scalar(@left) == 1);
  253.                         @balls = @left;
  254.                         push(@$ref_buf, @right);
  255.                         push(@$ref_buf, @others);
  256.                 }
  257.                 else
  258.                 {
  259.                         return shift(@right) if (scalar(@right) == 1);
  260.                         @balls = @right;
  261.                         push(@$ref_buf, @left);
  262.                         push(@$ref_buf, @others);
  263.                 }

  264.                 &ball_find3(\@balls, $heavy_flag, $ref_buf, $deep);
  265.         }
  266. }

  267. sub ball_total_heavy
  268. {
  269.         my $heavy = 0;
  270.         foreach my $ball (@{$_[0]})
  271.         {
  272.                 $heavy += $ball->[1];
  273.         }

  274.         return $heavy;
  275. }

  276. sub ball_show
  277. {
  278.         my $string = "";
  279.         foreach my $ball (@{$_[0]})
  280.         {
  281.                 my ($id, $heavy) = @$ball;
  282.                 $string .= "[$id,$heavy] ";
  283.         }

  284.         $string =~ s/\s+$//;
  285.         return $string;
  286. }

  287. sub ball_success
  288. {
  289.         my ($id, $heavy) = @{$_[0]};
  290.         print "\n缺陷球为:[$id,$heavy]\n";
  291. }

  292. sub ball_fail
  293. {
  294.         print "\n无解\n";
  295. }
复制代码

ball.zip

1.61 KB, 下载次数: 18

论坛徽章:
0
2 [报告]
发表于 2011-02-12 01:17 |只看该作者
本帖最后由 CrkED 于 2011-02-12 03:33 编辑

呵呵,刚好是俺上学期算法分析课的作业。最有效率的方法是用决策树模型。每个比较操作可能得到3种结果,所以这里的决策树是个三叉树。由于不知道是轻还是重,所以决策树可能的叶子节点一共有2*n个,所以lower bound=log3(2*n)。n=12的时候就是2.89<3。
ps1: 如果知道轻重,则可能的节点只有n个,此时lower bound=log3(n)。
ps2: 如果连是否存在与众不同的球都不知道,则lower bound=log3(2*n+1)。
ps3: 关于如何生成决策树,如c4.5算法,请自行google。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP