加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

数独算法之ALS

(2008-04-27 07:20:05)
标签:

游戏

很长时间了,一直没有头绪,已经把他放一边很久了,终于想起来用个周末的时间完成,虽然还有很多问题但是毕竟第一步开始了.

 

先说什么是ALS吧,ALS指Amost Lock Set,好象叫不完全锁定集,它的定义如下:

1:R1,R2中各存在一个集合M,M中的n个格中共有n+1个候选数,
  其中有两个候选数(y,z)只出现1次
2:有一个规则r,r中包含单格G1,G2,且G1∈R1,G2∈R2,y∈G1,y∈G2。
  记做y端,另一端包含z的叫z端(也就是两个集里只出现一次的数那个数在同一个规则内)
3:存在单格G3,z∈G3,分别与R1R2的z端在同一规则内。(有一格与另一个只出现一次的数(另外一端)分别在同一规则中)
4:G3中的z可以被删减。
5:此yz可做为链传递。
         y.......y
               \
   a---A           B---b
               /
         z...*...z
 
  为可删减的格

下面是个例题(这个题还可以用别的方法做,这里是说ALS)
 +-------------+-------------+-------------+
 | 24    | 24    | 1     |
 | 9    24  | 248 1   48  | 56   56  |
 | 5     | 7     | 8     |
 +-------------+-------------+-------------+
 | 28   23  | 458 7    |#35  #45  |
 |*17    | 3    14  | 2   #47  |
 | 178 4  *13  | 58   18  | 357 6    |
 +-------------+-------------+-------------+
 | 6     | 1     | 9     |
 | 14   14  | 9     | 67   67  |
 | 3     | 6     | 4     |
 +-------------+-------------+-------------+
A={R5C1,R6C3} 两个格包含3个辅数且3,7只出现1次
B={R4C7,R4C9,R5C9} 三个格包含4个辅数,且3,7只出现1次

同时A,B中包含共同的7,都只出现1次,而且两个格在同一规则内(行)
y=7
z=3

         7.......7
               \
   1---A           B---4,5
               /
         3...*...3

R6C7和R4C3都能同时看到A,B集的另外一端(R6C2,R4C7)

 * 有两个一个是R6C7是357,可以删减3,另一个是R4C3的23也可以删减3

//找到所有的ALS集

function als_find_a(&$arrdu,$tar)
{
 $tmp = '';
 foreach($tar as $t)$tmp.=$arrdu[$t];
 $tc = str_split(str_replace('0','',$tmp));
 $td = array_count_values($tc);
 asort($td);
 $te = implode(',',$td);
 $tals = array();
 if((count($td) == (count($tar)+1))  //
 && (substr($te,0,4) == '1,1,'))
 {
  $mk=0;
  $tals = array(0,0,0,0);
  $tmp = array();
  foreach($td as $tk => $tl)
  {
   $tmp[]=$tk;
   if($mk++ >= 1)break;
  }
  $place=4;
  $i=0;
  foreach($tar as $k)
  {
   $la =  (strpos($arrdu[$k],''.$tmp[0]) >0)? true : false;
   $lb =  (strpos($arrdu[$k],''.$tmp[1]) >0)? true : false;
   if($la xor $lb)
   {
    if($la)$tals[$i] = $tmp[0];
    else   $tals[$i] = $tmp[1];
    $tals[$i+2]=$k;
    $i++;
   }
   else { $tals[$place++] = $k;}
  }
 }
 if($tals[0] == 0 || $tals[1] == 0)return '';
 else return implode(',',$tals);;
}
function als_find(&$arrdu)
{
 //返回数组格式候选数y,候选数z,候选y所在位置,候选z所在位置,其它单元格位置
 //reutrn array[]=(y,z,Py,Pz,Pa1,Pa2,...)
 GLOBAL $rule,$initstr;
 
 $narr = str_split(substr($initstr,1)); //1,2,3,4,...

 $als = array();
 foreach($rule as $ru)
 {
  $m=0;
  foreach($ru as $j)if($arrdu[$j]{0} === '0')$m++;
  if($m<=2)continue; //最小的ALS由两个单元格(3个辅数)组成,单规则中未填格必大于2
  
  //第1个数
  if($m>2)
  foreach($ru as $i)if($arrdu[$i]{0} === '0')
  foreach($ru as $j)if(($i != $j) && ($arrdu[$j]{0} === '0')) //顺序不同的看成两个
  {
   //双格
   $tmp = als_find_a($arrdu,array($i,$j));
   if(strlen($tmp)>2)$als[]=$tmp;
   //三格
   if($m>3)foreach($ru as $k)if(($i != $k)&&($j != $k) && ($arrdu[$k]{0} === '0'))
   {
    $tmp = als_find_a($arrdu,array($i,$j,$k));
    if(strlen($tmp)>2)$als[]=$tmp;
    if($m>4)foreach($ru as $m)if(($i != $m)&&($j != $m)&&($k != $m) && ($arrdu[$m]{0} === '0'))
    {
     $tmp = als_find_a($arrdu,array($i,$j,$k,$m));
     if(strlen($tmp)>2)$als[]=$tmp;

        //以后可扩展到5格,再多就没意思了
    }
   }
   
 }
 return $als;
}

//专门用来输出一个ALS的 A1(B1,C2,D3)D5(超过2的)或 A1-A3
function als_outit($chain,$allpairs)
{
 $j=0;
 $t = array();
 foreach($chain as $i)
 {
  $ap = explode(',',$allpairs[$i]);
  if(count($ap)>4)$t[$j].=bit2place($ap[2])."(".implode(' ',array_map("bit2place",array_slice($ap,4))).")".bit2place($ap[3]);
  else $t[$j].=bit2place($ap[2])."-".bit2place($ap[3]);
  $j++;
 }
 return implode(':',$t);
}
function als_deepchains(&$arrdu,$num,$chain,&$allpairs)
{
 //$num 是链首数
 //$chain 是链集
 //$allpairs 是所有链
 GLOBAL $rule,$initstr,$r_row,$r_col,$r_box;
 
 $max = false;
 end($chain);
 $tp = current($chain); //B 
 $tp = explode(',',$allpairs[$tp]);
 
 for($j=0;$j<count($allpairs);$j++) //first pair  CD
 {
  $tj = $tq = explode(',',$allpairs[$j]);
  
  $tmp = $tj[0];$tj[0]=$tj[1];$tj[1]=$tmp;
  $tmp = $tj[2];$tj[2]=$tj[3];$tj[3]=$tmp;
  $k = array_search(implode(',',$tj),$allpairs);
  $savea = array();
  foreach($chain as $st)
  {
   $sb = explode(',',$allpairs[$st]);
   $savea[]=$sb[2];
   $savea[]=$sb[3];
  }
  if( !in_array($tq[2],$savea)
   && !in_array($tq[3],$savea)
   && ($tp[1] == $tq[0])
   //&& ishardlink($arrdu,$tp[1],$tp[3],$tq[2])) //不要求尾和首是强链 m
   && insamerule($tp[3],$tq[2])
   )
  {
  if($chain[0] == 25 && $j==27)echo "B $num \n";
   array_push($chain,$j);
  
   $first = true;
   //本层是否有解
   $tf = $chain[0];
   $tf = explode(',',$allpairs[$tf]);
   
   if($tq[1] == $num)
   foreach($arrdu as $m => $n)
   if($n{0} === '0'
   && ($m != $tf[2]) && ($m != $tq[3])
   && strpos($n,"$num") !== false
   && insamerule($m,$tf[2])
   && insamerule($m,$tq[3])
   )
   {
    //echo "$tm,$tf,$tp,$tq\n";
    if($first)
    {
     if($GLOBALS['deep'])$GLOBALS['diff'][24]++;
     if(!$GLOBALS['debug'])$first = false;
    }
    //有解
    $max = true;
    $new = str_replace("$num",'',$n);
    $arrdu[$m] = $new;
    if($GLOBALS['debug'])
    {
     if($first)
     {
      $first = false;
      echo "ALS($num):[ ".als_outit($chain,$allpairs)."]\n";
     }
     echo "            ".bit2place($m)." $n => $new \n";
     
   }
   //if($max)return $max;
   //下一层
   //if( als_deepchains($arrdu,$num,$chain,$allpairs))$max = true;
   array_pop($chain);
  }
 }
 return $max;
}

 


function als(&$arrdu)
{
 GLOBAL $rule,$initstr,$r_row,$r_col,$r_box;

 //outit2($arrdu);
 $als = array_unique(als_find($arrdu));
 sort($als);
 //print_r($als);
 if(count($als)>1)foreach($als as $k => $strals)
 {
  if($max = als_deepchains($arrdu,$strals{0},array($k),$als))
  {
   if(onlyone($arrdu)==-1)return -1;
   else return 1;
  }
 }
 
 
 return 0;
}

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有