您的位置:首页 > 编程语言 > PHP开发

php解:2006 年百度之星程序设计大赛复赛题目 4 ----彩球游戏

2011-06-05 20:48 363 查看
2006 年百度之星程序设计大赛复赛题目 4

彩球游戏

X 博士是一个研究儿童智力开发方法的科学家,他为幼儿教育领域做出了许多贡献。最近, X 博士正在研究一种适合儿童的游戏,用以辅助发展儿童的观察力、注意力和思维能力。经过连日的构思, X 博士终于设计出了一种游戏:彩球游戏。

彩球游戏是一种单人参与的游戏,游戏首先给出一串由许多不同颜色的小球组成的小球序列,以及一个整数参数 M ( M ≥ 2 )。一段连续的具有相同颜色的小球序列称为连续同色序列。小孩,即游戏参与者,每次可以向任意一段连续同色序列插入一个同色小球,使该序列的长度加一。当一段连续同色序列在插入一个同色小球后其长度达到 M 时,该序列就会爆炸消失,然后原序列两边的其余小球会重新连成一串,如果两段相同颜色的连续同色序列在此时连接在一起,它们就会合并形成一段新的连续同色序列。如果新形成的连续同色序列长度达到 M ,这段序列也会爆炸消失,然后重复上述过程,直到没有新的长度达到 M 的连续同色序列出现为止。游戏的目标很简单,就是插入尽量少的小球,使得所有小球都爆炸消失掉。

通过长时间的游戏和不断提高游戏水平,这个游戏可以很好地开发儿童的观察力、注意力和思维能力。但是 X 博士仍然面临着一个困难的问题,他还需要设计出一个游戏演示 AI 程序,可以以最优的方式(即插入的小球数量最小)进行游戏,用于游戏教学,或者在游戏中对小孩给出提示。 X 博士并不擅长此类程序,因而他无法完成这个任务,你可以帮助他吗?

输入格式:

输入文件包含多组测试数据。每组测试数据第一行为整数 M ( 2 ≤M≤20 ),第二行为一条非空的字符串,由大写字母组成且长度不超过 200 ,表示初始的一串小球,不同的字母表示不同的小球颜色。初始时可能会存在一些长度达到 M 的连续同色序列,但这些序列不会马上爆炸消失。

输出格式:

每组测试数据输出一行,表示至少需要插入多少次小球才能使所有小球爆炸消失掉。

输入样例:

3

AAABAAA

3

ABBABBA

输出样例:

2

2

说明:

共有 5 个测试数据集,每个测试数据集为一个输入文件,包含多组测试数据。每个测试数据集从易到难分别为 5 、 10 、 15 、 30 和 40 分,对每个测试数据集分别执行一次程序,每次必须在运行时限 30 秒内结束程序并输出正确的答案才能得分。

所有数据均从标准输入设备( stdin/cin )读入,并写出到标准输出设备 ( stdout/cout )中。

五个测试数据集中输入初始小球队列的长度分别不大于 10 、 20 、 50 、 100 和 200 ,各有不超过 5000 组测试数据。

基本方法:试着插入小球,根据可能,生成的树,到空时记录该棵树,树记录了每次插入的球列,插入该列的位置,插入后的新球列

PHP代码:我封装在函数了,/*
主函数说明:xiaoqiu($chushi,$min=3)
功能:具体的消球处理过程,得到消球得可能
参数说明:$chushi--------初始的要处理的球列字符串,$min=3---------爆炸最小连续量,默认3
返回值:返回满足条件的部分数组,第一条就是最少的次数
*/

只提取最少的PHP代码:

<?php
set_time_limit(0);
//begin 递归函数,获得爆炸后的球列
/*
函数说明:baozha($qiuarr,$wz,$min)
功能:递归,放置球,若发生爆炸,执行这个递归,判断其消球后是否仍可消
参数说明:$qiuarr--------球列按颜色解析后的数组;$wz--------爆炸位置;$min------会爆炸最小连续量
返回值:返回爆炸后的新的球列字符串,若空了,说明球全部消失,达到条件
*/
function baozha($qiuarr,$wz,$min){
//路过是中间区域爆炸,判断其是否会连续爆炸
if(0<$wz&&$wz<count($qiuarr)-1){
//echo 1;
$zuo=$wz-1;
$you=$wz+1;
$yanse1=$qiuarr[$zuo][0];
$yanse2=$qiuarr[$wz+1][0];
//路过下一次也会发生爆炸,连续爆炸
if($yanse1==$yanse2&&strlen($qiuarr[$zuo])+strlen($qiuarr[$wz+1])>=$min){
$t=array();
for($i1=0;$i1<$zuo;$i1++)$t[]=$qiuarr[$i1];//生成左边
$t[]=$qiuarr[$zuo].$qiuarr[$you];
for($i1=$wz+2;$i1<count($qiuarr);$i1++)$t[]=$qiuarr[$i1];//生成右边
$newqiulie=baozha($t,$zuo,$min);//递归获得新的球列
//print_r($t);
//echo $zuo;
}//end if($yanse1==$yanse2

else{
$t=array();
for($i1=0;$i1<=$zuo;$i1++)$t[]=$qiuarr[$i1];//生成左边
for($i1=$wz+1;$i1<count($qiuarr);$i1++)$t[]=$qiuarr[$i1];//生成右边
$newqiulie=implode('',$t);//新的球列
} //end 下一次不会爆炸

}//end if(0<$wz&&$wz<count($qiuarr)-1)
//路过不是中间区域爆炸,去掉爆炸部分
else{$zuo=$wz-1;
$t=array();
for($i1=0;$i1<=$zuo;$i1++)$t[]=$qiuarr[$i1];//生成左边
for($i1=$wz+1;$i1<count($qiuarr);$i1++)$t[]=$qiuarr[$i1];//生成右边
$newqiulie=implode('',$t);//新的球列

}

return $newqiulie;
}
//end 递归函数

/*
函数说明:qiulie_arr($qiulie)
功能:生成球的数组,按颜色区分
参数说明:$qiulie------处理的球列字符串
返回值:返回解析后的数组
*/

function qiulie_arr($qiulie)
{//解析球序列为同色的球数组
$qiuarr=array();
$yanse=$qiulie[0];
$str='';
for($i=0;$i<strlen($qiulie);$i++){
if($qiulie[$i]==$yanse){$str.=$qiulie[$i];if($i==strlen($qiulie)-1)$qiuarr[]=$str;}

else{
$qiuarr[]=$str;
$str=$qiulie[$i];
$yanse=$qiulie[$i];
if($i==strlen($qiulie)-1)$qiuarr[]=$str;
}

}
return $qiuarr;
}

/*
函数说明:xiaoqiu($chushi,$min=3)
功能:具体的消球处理过程,得到消球得可能
参数说明:$chushi--------初始的要处理的球列字符串,$min=3---------爆炸最小连续量,默认3
返回值:返回满足条件的部分数组,第一条就是最少的次数
*/

//演示消球得过程,选择最少次数
function xiaoqiu($chushi,$min=3)
{//球的图形,记录球列,每放置一次球,记录球列字符串,放置的位置,新的球列
//AAccABBAAcAA|放置的位置|新球列
//彩球游戏
//$qiustr='AArrwAAeeebAAbbeeAmma';//球的序列
//$chushi='AAccABBAAcAA';
if($chushi=='')die('错误:初始球列不能空');
echo '当前处理球列:'.$chushi.'<br>';
//$lian='||'.$qiustr;
$lianarr=array('');
$save=array();
$sequ=array();
$tuji=array($chushi);
//$min=4;//发生爆炸的最小量
$end=0;//取到一条有效树就结束
while(!empty($lianarr)&&$end==0){

$newarr=array();
//循环处理每种情况
for($i=0;$i<count($lianarr)&&$end==0;$i++){

$lian=$lianarr[$i];
if($lian!=''){$a=explode('-',$lian);
$len=count($a)-1;
$last=$a[$len];
$a1=explode('|',$last);
$qiulie=$a1[2];
}
else $qiulie=$chushi;
$qiuarr=qiulie_arr($qiulie);//解析球列为数组,按颜色划分
//球的爆炸和发射阶段
//发射,选择同色球位置,添加一个同色球
for($i1=0;$i1<count($qiuarr)&&$end==0;$i1++){
$wz=$i1;//发射位置
$qiuse=$qiuarr[$wz][0];//选择的球的颜色
$qiushu=strlen($qiuarr[$wz]);//球的连续数量

//大于等于最小量,发生爆炸
if($qiushu+1>=$min){
$newqiulie=baozha($qiuarr,$wz,$min);

}//end if($qiushu+1>=$min)

//路过没有发生爆炸,加入球
else{$t=$qiuarr;
$qiu=$qiuse.$qiuarr[$wz];
$t[$wz]=$qiu;
$newqiulie=implode('',$t);

}

//echo '新连='.$newqiulie;
$new=$qiulie.'|'.$wz.'|'.$newqiulie;//新单元
if($lian=='')$newstr=$new;
else $newstr=$lian.'->'.$new;
//路过是空的了 ,记录下来
if($newqiulie==''){
$save[]=$newstr;$end=1;break;
}
//不是空支付
else{//路过已有的图,舍弃
if(in_array($newqiulie,$tuji)){
//echo 1;
$sequ[]=$newstr;

}
//加入新图,更新树
else{
$tuji[]=$newqiulie;
$newarr[]=$newstr;
}

}

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

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

$lianarr=$newarr;

}//end while(!empty($lianarr))

return $save;

}

//下面是 一个测试,$min越小,测试球列越短,得到结果速度快;反之:会用些时间,路过只提取第一条,就不在获取,我想速度会加快很多,我是获取了多种可能的步骤

$chushi='ABBBBCCCCBADDDDAAAABEEEEBBBBAAAA';
$save=xiaoqiu($chushi,3);

echo '最后满足条件的数组:(说明:->是每次放球的分割,|分割单元3部分:1.左边是放置球之前的球列;2.中间是对该球列放置的位置,解析成同色的数组对应得索引位置;3.右边是放球后的新的球列):<br>';
print_r($save);
echo '<br><br>';
$a=explode('->',$save[0]);
$minbu=count($a);
echo '至少需要插入'.$minbu.'次小球才能使所有小球爆炸消失掉<br>';
echo '一个步骤是:'.$save[0];

?>

生成多种可能的PHP代码:

<?php
set_time_limit(0);
//begin 递归函数,获得爆炸后的球列
/*
函数说明:baozha($qiuarr,$wz,$min)
功能:递归,放置球,若发生爆炸,执行这个递归,判断其消球后是否仍可消
参数说明:$qiuarr--------球列按颜色解析后的数组;$wz--------爆炸位置;$min------会爆炸最小连续量
返回值:返回爆炸后的新的球列字符串,若空了,说明球全部消失,达到条件
*/
function baozha($qiuarr,$wz,$min){
//路过是中间区域爆炸,判断其是否会连续爆炸
if(0<$wz&&$wz<count($qiuarr)-1){
//echo 1;
$zuo=$wz-1;
$you=$wz+1;
$yanse1=$qiuarr[$zuo][0];
$yanse2=$qiuarr[$wz+1][0];
//路过下一次也会发生爆炸,连续爆炸
if($yanse1==$yanse2&&strlen($qiuarr[$zuo])+strlen($qiuarr[$wz+1])>=$min){
$t=array();
for($i1=0;$i1<$zuo;$i1++)$t[]=$qiuarr[$i1];//生成左边
$t[]=$qiuarr[$zuo].$qiuarr[$you];
for($i1=$wz+2;$i1<count($qiuarr);$i1++)$t[]=$qiuarr[$i1];//生成右边
$newqiulie=baozha($t,$zuo,$min);//递归获得新的球列
//print_r($t);
//echo $zuo;
}//end if($yanse1==$yanse2

else{
$t=array();
for($i1=0;$i1<=$zuo;$i1++)$t[]=$qiuarr[$i1];//生成左边
for($i1=$wz+1;$i1<count($qiuarr);$i1++)$t[]=$qiuarr[$i1];//生成右边
$newqiulie=implode('',$t);//新的球列
} //end 下一次不会爆炸

}//end if(0<$wz&&$wz<count($qiuarr)-1)
//路过不是中间区域爆炸,去掉爆炸部分
else{$zuo=$wz-1;
$t=array();
for($i1=0;$i1<=$zuo;$i1++)$t[]=$qiuarr[$i1];//生成左边
for($i1=$wz+1;$i1<count($qiuarr);$i1++)$t[]=$qiuarr[$i1];//生成右边
$newqiulie=implode('',$t);//新的球列

}

return $newqiulie;
}
//end 递归函数

/*
函数说明:qiulie_arr($qiulie)
功能:生成球的数组,按颜色区分
参数说明:$qiulie------处理的球列字符串
返回值:返回解析后的数组
*/

function qiulie_arr($qiulie)
{//解析球序列为同色的球数组
$qiuarr=array();
$yanse=$qiulie[0];
$str='';
for($i=0;$i<strlen($qiulie);$i++){
if($qiulie[$i]==$yanse){$str.=$qiulie[$i];if($i==strlen($qiulie)-1)$qiuarr[]=$str;}

else{
$qiuarr[]=$str;
$str=$qiulie[$i];
$yanse=$qiulie[$i];
if($i==strlen($qiulie)-1)$qiuarr[]=$str;
}

}
return $qiuarr;
}

/*
函数说明:xiaoqiu($chushi,$min=3)
功能:具体的消球处理过程,得到消球得可能
参数说明:$chushi--------初始的要处理的球列字符串,$min=3---------爆炸最小连续量,默认3
返回值:返回满足条件的部分数组,第一条就是最少的次数
*/

//演示消球得过程,选择最少次数
function xiaoqiu($chushi,$min=3)
{//球的图形,记录球列,每放置一次球,记录球列字符串,放置的位置,新的球列
//AAccABBAAcAA|放置的位置|新球列
//彩球游戏
//$qiustr='AArrwAAeeebAAbbeeAmma';//球的序列
//$chushi='AAccABBAAcAA';
if($chushi=='')die('错误:初始球列不能空');
echo '当前处理球列:'.$chushi.'<br>';
//$lian='||'.$qiustr;
$lianarr=array('');
$save=array();
$sequ=array();
$tuji=array($chushi);
//$min=4;//发生爆炸的最小量

while(!empty($lianarr)){

$newarr=array();
//循环处理每种情况
for($i=0;$i<count($lianarr);$i++){

$lian=$lianarr[$i];
if($lian!=''){$a=explode('-',$lian);
$len=count($a)-1;
$last=$a[$len];
$a1=explode('|',$last);
$qiulie=$a1[2];
}
else $qiulie=$chushi;
$qiuarr=qiulie_arr($qiulie);//解析球列为数组,按颜色划分
//球的爆炸和发射阶段
//发射,选择同色球位置,添加一个同色球
for($i1=0;$i1<count($qiuarr);$i1++){
$wz=$i1;//发射位置
$qiuse=$qiuarr[$wz][0];//选择的球的颜色
$qiushu=strlen($qiuarr[$wz]);//球的连续数量

//大于等于最小量,发生爆炸
if($qiushu+1>=$min){
$newqiulie=baozha($qiuarr,$wz,$min);

}//end if($qiushu+1>=$min)

//路过没有发生爆炸,加入球
else{$t=$qiuarr;
$qiu=$qiuse.$qiuarr[$wz];
$t[$wz]=$qiu;
$newqiulie=implode('',$t);

}

//echo '新连='.$newqiulie;
$new=$qiulie.'|'.$wz.'|'.$newqiulie;//新单元
if($lian=='')$newstr=$new;
else $newstr=$lian.'->'.$new;
//路过是空的了 ,记录下来
if($newqiulie==''){
$save[]=$newstr;
}
//不是空支付
else{//路过已有的图,舍弃
if(in_array($newqiulie,$tuji)){
//echo 1;
$sequ[]=$newstr;

}
//加入新图,更新树
else{
$tuji[]=$newqiulie;
$newarr[]=$newstr;
}

}

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

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

$lianarr=$newarr;

}//end while(!empty($lianarr))

return $save;

}

//下面是 一个测试,$min越小,测试球列越短,得到结果速度快;反之:会用些时间,路过只提取第一条,就不在获取,我想速度会加快很多,我是获取了多种可能的步骤

$chushi='ABBACCADDA';
$save=xiaoqiu($chushi,3);

echo '最后满足条件的数组:(说明:->是每次放球的分割,|分割单元3部分:1.左边是放置球之前的球列;2.中间是对该球列放置的位置,解析成同色的数组对应得索引位置;3.右边是放球后的新的球列):<br>';
print_r($save);
echo '<br><br>';
$a=explode('->',$save[0]);
$minbu=count($a);
echo '至少需要插入'.$minbu.'次小球才能使所有小球爆炸消失掉<br>';
echo '一个步骤是:'.$save[0];

?>

测试效果图:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: