- 论坛徽章:
- 0
|
本帖最后由 iamlimeng 于 2013-10-28 14:10 编辑
猜数字游戏是一个比较老的智力游戏,较早出现在文曲星上,曾经流行过,规则如下:
由电脑随机生成一个由0-9组成的四位数(规则:可以由0开头,不能有重复数字,比如1123就不符合规则,0123符合规则),每猜一个数字,电脑就根据这个数字给出几A几B,其中A前面的数字表示数字和位置均正确的数的个数,而B前的数字表示数字正确而位置不对的数的个数。如正确答案为5234 而猜的人猜 5346,则是 1A2B,其中有一个5的位置对了,记为1A,而3和4这两个数字对了,而位置没对,因此记为 2B,合起来就是 1A2B。接着猜的人再根据出题者的几A几B继续猜,直到猜中(即 4A0B)为止。
步数计算规则:程序提示4A0B为最后一步,而不是以已经知道答案那一步为最后一步。
到目前为止,已知的解法是最多猜7步全中,平均5.213步。这种解法不是通过算法实现的,而是统计得来的,个人认为如果算法优秀,还有提升空间。
已知的算法比较多,比如可能集递归法,最大信息量法、最坏情况指标法等。本人实现的最佳算法:最多猜8步全中,平均5.295步。可能集递归法速度最快,最多猜8步全中,平均5.442步。统计方式为:把所有可能的5040个数字循环猜一遍,然后进行统计。
游戏见附件。Perl实现的代码我也有,但由于不是本人所写,故不公布。将我下面求解的代码修改即可轻松实现。
可能集递归法代码:- #!/usr/bin/perl -w
- use strict;
- use warnings;
- #生成有效数字集
- my $number = '0123';
- my @valid; #5040个有效数字
- while (length($number) == 4) {
- my $valid = 1;
- foreach (split('',$number)) {
- my $counts = () = ($number =~ /$_/g);
- if ($counts > 1) {
- $valid = 0;
- last;
- }
- }
- push(@valid,"$number") if ($valid);
- $number++;
- }
- #求解,并进行统计输出
- my @valid_temp = @valid;
- my %count_guess = ();
- open(FH,">count_guess.xls");
- print FH "Answer Number\tGuess Times";
- foreach (1..8) { print FH "\tStep $_"; }
- print FH "\n";
- foreach my $answer(@valid) {
- my $n = 1;
- my $steps = '';
- while (1) {
- my $number;
- if ($n == 1) { $number = $valid[0]; }
- else { $number = $valid_temp[int(@valid_temp/2)]; }
- #每次取可能集中居中的数字为下一次猜的数字
- #若随机取,最多步数为9步,个别情况为10步
- my $judge = judge($number,$answer);
- guess($number,$judge);
- $steps .= "\t$number:$judge";
- if ($judge eq '4A0B') {
- $count_guess{$n}++;
- print FH "$answer\t$n$steps\n";
- last;
- }
- $n++;
- }
- print "$answer\t$n\n";
- @valid_temp = @valid;
- }
- my ($guess_times,$guess_values) = (0,0);
- print FH "\n";
- foreach my $n (sort keys %count_guess) {
- $guess_times += $count_guess{$n};
- $guess_values += $n * $count_guess{$n};
- print FH "$n\t$count_guess{$n}\n";
- }
- print FH "Total\t$guess_times\n";
- print FH "Average\t",sprintf("%.3f",$guess_values/$guess_times),"\n";
- close FH;
- sub guess { #求可能集
- my ($number,$judge) = @_;
- my @valid_search = @valid_temp;
- @valid_temp = ();
- foreach my $no (@valid_search) {
- push(@valid_temp,$no) if (judge($no,$number) eq $judge);
- }
- }
- sub judge { #求判断码
- my($n,$g) = @_;
- my ($a,$b)=(0,0);
- foreach (0..3) {
- my $str_n = substr($n,$_,1);
- if ($str_n eq substr($g,$_,1)) { $a++; }
- elsif ($g =~ /$str_n/) { $b++; }
- }
- return ($a.'A'.$b.'B');
- }
复制代码 个人以为,通过优秀算法,有望将最大猜测步数减少到6步以内,若大家有更好的算法,希望共同探讨。
Guess_Number.rar
(9.73 KB, 下载次数: 91)
|
|