php解:百度之星2009程序设计大赛 初赛第一场试题--------火柴游戏

百度之星2009程序设计大赛 初赛第一场试题

2009年5月30日19:00-22:30(由于第二题出错,比赛时间延长半小时),2008百度之星大赛在线资格赛(初赛)展开。百度爱好者(Baiduer.com.cn)在第一时间给大家带了初赛题目。第一场初赛共四题,分别是火柴游戏(250分)、电子商务平台商品推荐问题 (300分)、争车位(300分)和葫芦娃 (350分),总计1200分。

1. 火柴游戏(250分)

题目描述

在百度,同事们之间喜欢交流游戏。其中,火柴游戏是一个比较经典的例子。游戏的规则很简单:恰好移动一根火柴,使等式成立。如下面的等式可以变成3+6=9(还有其他解):移动哪一根火柴能使等式成立?

match

下面是所有火柴数字的样子

match_digit

请你写一个程序,找出所有的规范解。所谓规范是指:

    * 只能改变数字,不能改变符号;

    * 数字和符号的组成方式必须严格的和图示的一样(减号由一根火柴组成);

    * 新等式必须形如a+b=c或a-b=c,其中a、b、c都是不含前导0的非负整数。

当然,最重要的是:新的等式必须在数学上成立。

输入格式

输入仅一行,为一个格式为a+b=c或a-b=c的表达式,其中a、b、c均为不含前导0的非负整数。表达式长度不超过100,且不含空白字符。因此,加号/减号紧跟在a的后面、 b紧跟在加号/减号的后面、等号紧跟在b的后面、c紧跟在等号的后面。

输出格式

输出所有规范解,按字典序输出(请注意:输出顺序不对将不得分)。无解时,仅输出一行-1。

样例输入1

9+5=9

样例输出1

3+5=8

3+6=9

样例输入2

1+1=2

样例输出2

-1

测试数据

共10个测试点,基本参数如下表:

测试点编号表达式的长度
1-21-10
3-410-25
5-626-50
7-1051-100

裁判问答:

Q:第一题的表达式长度不是只有5吗?  A:可以多位整数

Q:把某根移出来再移到原来的位置上算不算移动? A:不算

 

 

基本方法:以0-9数字为移动对象,对于多位数,只要把表达式数字0-9提取出来,并记录他们所在的数字单元,路456中4是456里德。初始解析字符串获得所有数字,连成一串,只处理数字,对于0-9这些数字,他们可以通过1.自身移动火柴2.向外移动,减一根火柴;3.添一根火柴的方式变成其他的数字,重耳实现变换表达式,可能出现等于的情况。

 

0-9数字的减1,加1,自身移动,情况有很大不同,需要分别列举出来,可以用数组映射这些移动后变化的数字

 

以一个数字移动分为1.对其自身的移动,2.对其他位置的加火柴

 

多位数首位置不能0,可以通过记录的该数字在其单元中的索引位置,判断,并且单元长度大于0,那么就舍去这种移位

 

 

 

 

 

 

 

PHP代码录下:我只用了几个简单的例子测试,不确定正确性,最后打印出满住的等式数组,并有些移动位置的说明

 

 

 

 

 

 

 

<?php

function dengshi($jiashu,$fuhao){
//求左右和
$shizi=array();
$he=array();
for($i=0;$i<2;$i++){
$he[$i]=0;
$shizi[$i]='';
for($j=0;$j<count($jiashu[$i]);$j++){
if($fuhao[$i][$j]=='+'){$he[$i]=$he[$i]+$jiashu[$i][$j];if($j==0)$shizi[$i].=$jiashu[$i][$j];else $shizi[$i].='+'.$jiashu[$i][$j];}
else{ $he[$i]=$he[$i]-$jiashu[$i][$j];$shizi[$i].='-'.$jiashu[$i][$j];}
}//end for($j=0;$j<count($jiashu[$i])

}//end for($i=0;$i<2;$i++)

//print_r($he);

//生成表达式过程

$shizistr=$shizi[0].'='.$shizi[1];

if($he[0]==$he[1])return $shizistr;
else return false;
}

//   0 1 2 3 4 5 6 7 8 9
//解析表达式,9+5=9,分成左右2部分,
$fustr='9+5=9';
$fuhao=array();//符号数组
$fuhao[0][0]='+';
$fuhao[1][0]='+';
$shuzi=array();
$jiashu=array();
$index=0;//索引
$jishu1=0;//计数器
$jishu2=0;//记录数字字符串左右分割位置
$fenwz=0;//分割位子
$quid=0;
$quwz=0;
$str='';
$save=array();
for($i=0;$i<strlen($fustr);$i++){
//路过是数字,记录
if(is_numeric($fustr[$i])){
$shuzi[$jishu1]=array($fustr[$i],$quid,$quwz,$index);
$jishu1++;
$quwz++;
$str.=$fustr[$i];
if($i==strlen($fustr)-1)$jiashu[$index][$quid]=$str;
}//end if(is_numeric($fustr[$i]))
else{$jiashu[$index][$quid]=$str;
$str='';
$quwz=0;
$quid++;
if($fustr[$i]=='+'){
$fuhao[$index][]='+';

}//end if($fustr[$i]=='+')

else if($fustr[$i]=='-'){
$fuhao[$index][]='-';
}
//当遇到den那个号时,把index加1,quid归0,记录右边的
else{$fenge=$jishu1-1;
$quid=0;
echo 1;
$index++;
}


}//end else


}//end for($i=0;$i<strlen($fustr)


print_r($shuzi);
print_r($jiashu);

print_r($fuhao);

echo '<br><br>';
//移动火采的过程


$unmove1=array(1,4,7,8);//不能自身移动得数字
$move1=array(0=>array(9,6),2=>array(3),3=>array(5),5=>array(3),6=>array(0,9),9=>array(6,0));//自身移动得数字,移动后变为的数字

$unmove2=array(0,1,2,3,4,5);//不能向外移动得数字
$move2=array(6=>array(5),7=>array(1),8=>array(0,6,9),9=>array(5,3));//可以外移动得数字,移动后变为的数字

$unmove3=array(2,4,7,8);//不能添火柴得数字
$move3=array(0=>array(8),1=>array(7),3=>array(9),5=>array(9,6),6=>array(8),9=>array(8));//可以添火柴得数字


//具体的移动过程
//遍历数字,每个数字都有可能自己移动和向外移动,向外需要添加方可以接受火采
for($i=0;$i<count($shuzi);$i++){
$shu=$shuzi[$i][0];//数字0-9
$index=$shuzi[$i][3];//左右区分
$wz=$shuzi[$i][2];//所属单元位置
$danyuan=$shuzi[$i][1];//所属单元位置id
//判断自身移动,要过过滤数组
if(!in_array($shu,$unmove1))//路过可以自身移动
{
$arr=$move1[$shu];//取其对应映射的数组
//进行对数字单元数组的转变
for($i1=0;$i1<count($arr);$i1++){
if($wz==0&&$arr[$i1]==0&&strlen($jiashu[$index][$danyuan])>1)continue;//路过变化后为0,且在单元第一位,跳过
$jiashu1=$jiashu;//建立加数数组,对其修改
$str=$jiashu1[$index][$danyuan];//所属单元字符串
//对该位加数转变,找到转换位置,重构字符串
$str1='';
for($i2=0;$i2<strlen($str);$i2++){
if($wz==$i2)$str1.=$arr[$i1];

else $str1.=$str[$i2];
}//end  for($i2=0;$i2<strlen($str);$i2++)

$jiashu1[$index][$danyuan]=$str1;//更新加数数组的一个单元
echo '自己移动:单元:'.$danyuan.'; 第几个:'.$wz.'; '.$shu.'--('.$str1.')<br>';
if($dengshi=dengshi($jiashu1,$fuhao))$save[]=$dengshi.' 说明:自己移动:等号左右:'.$index.'(0左,1右); 单元:'.$danyuan.'; 第几个:'.$wz.'; '.$shu.'--('.$str1.')<br>' ;//路过相等,保存


}//end for($i1=0;$i1<count($arr);$i1++)

}//end if(!in_array($shu,$unmove1))

//进行向外移动,判断是否可以外移,并且添加方可以接受火柴
if(!in_array($shu,$unmove2)){
echo 2;
//生成对应的映射数组
$arr1=$move2[$shu];
//向其他位置添加火柴
for($i3=0;$i3<count($shuzi);$i3++){

if($i==$i3)continue;//路过遇自身,跳过,前面已经判断
if(in_array($shuzi[$i3][0],$unmove3))continue;//路过不能添加,跳过
$shu1=$shuzi[$i3][0];//数字0-9
$index1=$shuzi[$i3][3];//左右区分
$wz1=$shuzi[$i3][2];//所属单元位置
$danyuan1=$shuzi[$i3][1];//所属单元位置id
$arr2=$move3[$shuzi[$i3][0]];//对应的添加数组
//生成2维循环,生成每种可能的组合,找到等式
for($i4=0;$i4<count($arr1);$i4++){
if(($wz==0&&$arr1[$i4]==0)&&strlen($jiashu[$index][$danyuan])>1)continue;//外移后为0,且在1位
//得到减火柴后的数字单元
$str1='';
$danyuanstr=$jiashu[$index][$danyuan];//所属单元字符串
for($a1=0;$a1<strlen($danyuanstr);$a1++){

if($a1==$wz){$str1.=$arr1[$i4];echo 3;}
else $str1.=$danyuanstr[$a1];

}//end for($a1=0;$a1<strlen($danyuanstr);


for($i5=0;$i5<count($arr2);$i5++){
if($wz1==0&&$arr2[$i5]==0&&strlen($jiashu[$index1][$danyuan1])>1)continue;

 $str2='';
$danyuanstr=$jiashu[$index1][$danyuan1];//所属单元字符串
for($a1=0;$a1<strlen($danyuanstr);$a1++){

if($a1==$wz1)$str2.=$arr2[$i5];
else $str2.=$danyuanstr[$a1];

}//end for($a1=0;$a1<strlen($danyuanstr)

$temparr=$jiashu;
echo '向外移动:单元:'.$danyuan.'; 第几个:'.$wz.'; '.$shu.'('.$str1.')--单元:'.$danyuan1.'; 第几个:'.$wz1.'; '.$shu1.'('.$str2.')<br>';
$temparr[$index][$danyuan]=$str1;
$temparr[$index1][$danyuan1]=$str2;

if($jieguo=dengshi($temparr,$fuhao))$save[]=$jieguo.'  说明:向外移动:等号左右:'.$index.'(0左,1右);单元:'.$danyuan.'; 第几个:'.$wz.'; '.$shu.'('.$str1.')--单元:'.$danyuan1.'; 第几个:'.$wz1.'; '.$shu1.'('.$str2.')<br>';

 

}//end for($i5=0;$i5<count($arr2)

 

 

}//end for($i4=0;$i4<count($arr1)

}//end for($i3=0;$i3<count($shuzi)

}//end if(!in_array($shu,$unmove2))


}//end for($i=0;$i<count($shuzi);$i++)


print_r($save);


?>

 

 

 

 

测试效果图

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值