View Single Post
  #4 (permalink)  
Old 2003-08-26, 02:13 PM
Transistor Transistor is offline
Junior Member
 
Join Date: Aug 2003
Posts: 2
Transistor
Default

Hi,
thank you for the congratulations.
Here is my solution including the annotations. ...if somebody is interested

Code:
<?php
$time_start = getmicrotime();
$try = 0;
//////////////////////////////////////////////////////
$iResultLength = -1;  	// result length
$arrResultPath = array();  // result path

// load map
$arrNodes = $arrNodeToWay = $arrNodeFromWay = array();
foreach(file("map.txt") as $sLine){
	$arrLine = explode(" ",strtoupper(trim($sLine)));
	if((sizeof($arrLine)==4) && $arrLine[0]!=$arrLine[2]){	// ignore empty/damaged lines and routes that start and end at the same point
 if(!isset($arrNodes[$arrLine[0]][$arrLine[2]]) || $arrNodes[$arrLine[0]][$arrLine[2]]>$arrLine[1]){
 	$arrNodes[$arrLine[0]][$arrLine[2]] = $arrLine[1];
 	if(!isset($arrNodeToWay[$arrLine[2]]) || $arrLine[1]<$arrNodeToWay[$arrLine[2]]){
  $arrNodeToWay[$arrLine[2]] = $arrLine[1];
 	}
 	if(!isset($arrNodeFromWay[$arrLine[0]]) || $arrLine[1]<$arrNodeFromWay[$arrLine[0]]){
  $arrNodeFromWay[$arrLine[0]] = $arrLine[1];
 	}
 }
 if($arrLine[3]==2){    	// bidirectional
 	if(!isset($arrNodes[$arrLine[2]][$arrLine[0]]) || $arrNodes[$arrLine[2]][$arrLine[0]]>$arrLine[1]){
  $arrNodes[$arrLine[2]][$arrLine[0]] = $arrLine[1];
  if(!isset($arrNodeToWay[$arrLine[0]]) || $arrLine[1]<$arrNodeToWay[$arrLine[0]]){
  	$arrNodeToWay[$arrLine[0]] = $arrLine[1];
  }
  if(!isset($arrNodeFromWay[$arrLine[2]]) || $arrLine[1]<$arrNodeFromWay[$arrLine[2]]){
  	$arrNodeFromWay[$arrLine[2]] = $arrLine[1];
  }
 	}
 }
	}
}

// take the shortes way first
reset($arrNodes);
while(list($sKey,) = each($arrNodes)){
	asort($arrNodes[$sKey],SORT_NUMERIC);
}

// load delivery instructions
$arrDelivery = array();
foreach(file("dest.txt") as $sLine){
	if($sLine = trim($sLine)) $arrDelivery = explode(" ",strtoupper($sLine));
}
$sDelivery = implode("",$arrDelivery);
#usort($arrDelivery,"cmpDeliveryNode");
$arrCountDelivery = array_count_values($arrDelivery);

// calculate delivery route
foreach($arrDelivery as $sStartPoint){
	if(isset($GLOBALS["arrNodes"][$sStartPoint])){	// if there is at least one destination node
 processNode(array($sStartPoint),0);
	}
}
echo implode(" ",array_intersect($arrResultPath,$arrDelivery))." ".$iResultLength." ".$try;

function processNode($arrPath,$iLength){

	global $arrNodes,
 	$arrCountDelivery,
 	$arrDelivery,
 	$sDelivery,
 	$arrNodeFromWay,
 	$arrNodeToWay,
 	$iResultLength,
 	$arrResultPath;

++$GLOBALS["try"];

	$sPath = implode("",$arrPath);
	$iStartElement = end($arrPath);
	$iLastElement = prev($arrPath);
	$arrCountPath = array_count_values($arrPath);

	// not yet processed points first
	$arrFirst = $arrSecond = $arrThird = array();
	foreach($arrNodes[$iStartElement] as $sDest=>$iLengthDest){

 if(!isset($arrCountPath[$sDest])){
 	if(isset($arrCountDelivery[$sDest])){
  $arrFirst[$sDest] = $iLengthDest; 	// not visited but on delivery route
 	}
 	else{
  $arrSecond[$sDest] = $iLengthDest; 	// not visited and not on route
 	}
 }
 else{
 	// ignore this when B is not on route for A B (A) or has been visited already
 	if($iLastElement !== $sDest || ($arrCountPath[$iStartElement]<2 && isset($arrCountDelivery[$iStartElement]))){
  $arrThird[$sDest] = $iLengthDest;  // already visited
 	}
 }
	}

	$arrTodo = array_diff($arrDelivery,$arrPath);
	foreach($arrFirst+$arrSecond+$arrThird as $sDest=>$iLengthDest){

 $iEstimatedMinLength = $iTmpLength = $iLength+$iLengthDest;

 $arrPathTmp = $arrPath;
 $arrPathTmp[] = $sDest;
 $arrTodoTmp = $arrTodo;
 if(($iDestKey = array_search($sDest,$arrTodoTmp))!==FALSE){
 	unset($arrTodoTmp[$iDestKey]);
 }
 if($arrTodoTmp && !array_intersect($arrTodoTmp,array_keys($arrNodes[$sDest]))){
 	$iEstimatedMinLength += $arrNodeFromWay[$sDest];
 }
 foreach($arrTodoTmp as $sDeliveryElement){
 	$iEstimatedMinLength += $arrNodeToWay[$sDeliveryElement];
 }
 // path longer than found one 
 if($iResultLength>=0 && $iEstimatedMinLength>=$iResultLength){
 	continue; // maybe another way is shorter -> go on
 }
 // all points processed -> shortest way found
 if(!$arrTodoTmp){
 	$iResultLength = $iTmpLength;
 	$arrResultPath = $arrPathTmp;
# 	echo implode("",$arrPathTmp).": $iTmpLength\n";
 	break; 	// this was the last missing point -> skip the rest
 }

 // don't drive useless circles again and again
 if(($iPos = strrpos($sPath,$sDest))!==FALSE){
 	$sSearch = substr($sPath.$sDest,$iPos+1);
 	$sSearchLength = strlen($sSearch);
 	if((strcspn($sSearch,$sDelivery)===$sSearchLength-1)  	// no destination point in circle
   || substr($sPath,($sSearchLength*-2)+1,$sSearchLength)===$sSearch	// ABCABC
   || strpos($sPath,$sDest.$sSearch)!==FALSE){   // A BCDB EFG BCDB
  continue;	// maybe another way is better -> go on
 	}
 }
 if(isset($arrNodes[$sDest])){	// if there is at least one destination node
 	processNode($arrPathTmp,$iTmpLength);
 }
	}
}

// nodes with less and longer connections first
function cmpDeliveryNode($a,$b){
	global $arrNodes;
	if(isset($arrNodes[$a]) && isset($arrNodes[$b])){
 $aSize = sizeof($arrNodes[$a]);
 $bSize = sizeof($arrNodes[$b]);
 if($aSize==$bSize){
 	if($aSize==1){
  $aLength = end($arrNodes[$a]);
  $bLength = end($arrNodes[$b]);
  if($aLength==$bLength) return 0;
  else return($aLength>$bLength)?-1:1;
 	}
 	else return 0;
 }
 else return($aSize<$bSize)?-1:1;
	}
	else return 0;
}

//////////////////////////////////////////////////////
echo "\n\n".(getmicrotime()-$time_start);

function getmicrotime(){
	list($usec, $sec) = explode(" ",microtime());
	return ((float)$usec + (float)$sec);
}
?>
Transistor
Reply With Quote