|
<?php |
|
|
|
// hybride liste |
|
$graphe = [ |
|
"Londres" => [ |
|
"Calais" => 61, |
|
"Paris" => 146 |
|
], |
|
"Calais" => [ |
|
"Paris" => 173, |
|
"Londres" => 61 |
|
], |
|
"Paris" => [ |
|
"Londres" => 146, |
|
"Calais" => 173, |
|
"Rennes" => 114, |
|
"Bordeaux" => 155, |
|
"Lyon" => 107 |
|
], |
|
"Rennes" => [ "Paris" => 114 ], |
|
"Bordeaux" => [ |
|
"Paris" => 155, |
|
"Toulouse" => 131 |
|
], |
|
"Lyon" => [ |
|
"Paris" => 107, |
|
"Montpellier" => 182, |
|
"Marseille" => 125 |
|
], |
|
"Toulouse" => [ |
|
"Bordeaux" => 131, |
|
"Montpellier" => 247 |
|
], |
|
"Montpellier" => [ |
|
"Toulouse" => 247, |
|
"Lyon" => 182 |
|
], |
|
"Marseille" => [ "Lyon" => 125 ], |
|
"Berlin" => ["Zurich" => 536], |
|
"Zurich" => ["Berlin" => 536] |
|
]; |
|
|
|
//représentation procédurale |
|
class Station{ |
|
public function __construct($name){ |
|
$this->name = $name; |
|
} |
|
|
|
public function __toString(){ |
|
return "Station <{$this->name}>"; |
|
} |
|
} |
|
|
|
class Trajet{ |
|
public function __construct(Station $start, Station $finish, $time){ |
|
$this->start = $start; |
|
$this->finish = $finish; |
|
$this->time = $time; |
|
} |
|
} |
|
|
|
class Graph{ |
|
private $stations; |
|
private $trajets; |
|
|
|
public function __construct($hybrid_representation){ |
|
$this->stations = |
|
array_combine( |
|
array_keys($hybrid_representation), |
|
array_map( |
|
function($city_name){ |
|
return new Station($city_name); |
|
}, |
|
array_keys($hybrid_representation) |
|
) |
|
); |
|
|
|
$this->trajets = []; |
|
foreach($hybrid_representation |
|
as $start_name => $destinations){ |
|
$start = $this->stations[$start_name]; |
|
foreach($destinations as $finish_name => $time){ |
|
$finish = $this->stations[$finish_name]; |
|
$trajet = new Trajet($start, $finish, $time); |
|
$this->trajets[] = $trajet; |
|
} |
|
} |
|
} |
|
|
|
/** |
|
* return Station |
|
**/ |
|
public function getStation($name){ |
|
//le graphe = $this |
|
return $this->stations[$name]; |
|
} |
|
|
|
/** |
|
* return Trajet |
|
**/ |
|
public function getTrajet($start, $finish){ |
|
//le graphe = $this |
|
$found = array_filter($this->trajets, function($t) use ($start, $finish){ |
|
return $t->start == $start && $t->finish == $finish; |
|
}); |
|
if(count($found) == 1){ |
|
return current($found); |
|
}else{ |
|
return null; |
|
} |
|
} |
|
|
|
/** |
|
* return Station[] |
|
**/ |
|
public function stations(){ |
|
//le graphe = $this |
|
return $this->stations; |
|
} |
|
|
|
/** |
|
* return Trajet[] |
|
**/ |
|
public function trajetsStartingAt(Station $start){ |
|
//on récupère tous les trajets dont Toulouse |
|
//est le point de départ |
|
$trajets_depuis_start = array_filter( |
|
$this->trajets, |
|
function($t) use ($start){ |
|
return $t->start == $start; |
|
}); |
|
|
|
//on trie les trajets par temps |
|
usort($trajets_depuis_start, function($t1, $t2){ |
|
return $t1->time > $t2->time; |
|
}); |
|
|
|
return $trajets_depuis_start; |
|
} |
|
|
|
/** |
|
* return Station[] |
|
**/ |
|
public function neigboursOf(Station $start){ |
|
//le graphe = $this |
|
$trajets_depuis_start = $this->trajetsStartingAt($start); |
|
|
|
//pour chaque trajet eligible |
|
//je renvois la ville de destination |
|
$neigbours = array_map(function($t){ |
|
return $t->finish; |
|
}, $trajets_depuis_start); |
|
|
|
return $neigbours; |
|
} |
|
|
|
/** |
|
* return Station[] |
|
**/ |
|
public function reachableStations(Station $start, $visited = []){ |
|
$isInitial = empty($visited); |
|
|
|
$visited[$start->name] = $start; |
|
$trajets = $this->trajetsStartingAt($start); |
|
|
|
foreach($trajets as $trajet){ |
|
|
|
if(!in_array($trajet->finish, $visited)){ |
|
$visited = $this->reachableStations($trajet->finish, $visited); |
|
} |
|
} |
|
|
|
if($isInitial){ |
|
unset($visited[$start->name]); |
|
} |
|
|
|
return $visited; |
|
} |
|
|
|
/** |
|
* return boolean |
|
**/ |
|
public function canGoFromTo(Station $from, Station $to){ |
|
return in_array($to, $this->reachableStations($from)); |
|
} |
|
|
|
/** |
|
* return Itineraire |
|
**/ |
|
public function plusCourtChemin(Station $from, Station $to){ |
|
return new Itineraire([]); |
|
} |
|
|
|
} |
|
|
|
class Itineraire{ |
|
public function __construct(/*Trajet[]*/ $trajets){ |
|
$this->trajets = $trajets; |
|
shuffle($this->trajets); |
|
} |
|
|
|
public function orderedTrajets() /* Trajet[] */{ |
|
|
|
//on liste toutes les villes |
|
$departs = array_map(function($t){ |
|
return $t->start; |
|
}, $this->trajets); |
|
$arrivals = array_map(function($t){ |
|
return $t->finish; |
|
}, $this->trajets); |
|
|
|
$allcities = array_unique(array_merge($departs, $arrivals)); |
|
|
|
// on trouve le départ et l'arrivée |
|
$true_start = array_diff($allcities, $arrivals); |
|
$true_arrival = array_diff($allcities, $departs); |
|
|
|
if(count($true_start) != 1){ |
|
throw new Exception("Erreur sur les départs"); |
|
} |
|
if(count($true_arrival) != 1){ |
|
throw new Exception("Erreur sur les arrivées"); |
|
} |
|
$true_start = current($true_start); |
|
$true_arrival = current($true_arrival); |
|
|
|
// on ordonne les stations dans le bon ordre |
|
$current_to = $true_start; |
|
$ordered_trajets = []; |
|
do{ |
|
//tant qu'on est pas arrivé au bout |
|
foreach($this->trajets as $k => $trajet){ |
|
// on cherche si un trajet part de là où on en est |
|
if($trajet->start == $current_to){ |
|
// si c'est le cas, on ajoute ce trajet à la suite |
|
$ordered_trajets[] = $trajet; |
|
$current_to = $trajet->finish; |
|
break; |
|
} |
|
} |
|
}while($current_to != $true_arrival); |
|
|
|
|
|
return $ordered_trajets; |
|
|
|
} |
|
|
|
public function visitedStations() /* Station[] */{ |
|
$ordered_trajets = $this->orderedTrajets(); |
|
$stations = []; |
|
foreach($ordered_trajets as $trajet){ |
|
if(empty($stations)){ |
|
$stations[] = $trajet->start; |
|
} |
|
$stations[] = $trajet->finish; |
|
} |
|
return $stations; |
|
} |
|
|
|
|
|
public function duration() /* int */{ |
|
$duration = 0; |
|
foreach($this->trajets as $trajet){ |
|
$duration += $trajet->time; |
|
} |
|
return $duration; |
|
} |
|
} |
|
|
|
$paris = new Station("Paris"); |
|
$lyon = new Station("Lyon"); |
|
$montpellier = new Station("Montpellier"); |
|
$toulouse = new Station("Toulouse"); |
|
$rennes = new Station("Rennes"); |
|
|
|
$itineraire = new Itineraire([ |
|
new Trajet($lyon, $montpellier, 182), |
|
new Trajet($montpellier, $toulouse, 247), |
|
new Trajet($paris, $lyon, 107), |
|
] |
|
); |
|
|
|
$visited = $itineraire->visitedStations(); |
|
echo "Liste des stations de l'itinéraire\n"; |
|
foreach($visited as $station){ |
|
echo "\t- ".$station."\n"; |
|
} |
|
//Paris, Lyon, Marseille |
|
echo $itineraire->duration(); |
|
//180 |
|
|
|
$tgv_france = new Graph($graphe); |
|
|
|
echo "Liste des stations\n"; |
|
foreach($tgv_france->stations() as $station){ |
|
echo "\t- ".$station."\n"; |
|
} |
|
|
|
echo "Voisins de Calais :\n"; |
|
$initial = $tgv_france->getStation("Calais"); |
|
foreach($tgv_france->neigboursOf($initial) as $station){ |
|
echo "\t- ".$station."\n"; |
|
} |
|
|
|
echo "Voisins de Berlin :\n"; |
|
$initial = $tgv_france->getStation("Berlin"); |
|
foreach($tgv_france->neigboursOf($initial) as $station){ |
|
echo "\t- ".$station."\n"; |
|
} |
|
|
|
echo "Atteignable depuis Berlin :\n"; |
|
$initial = $tgv_france->getStation("Berlin"); |
|
foreach($tgv_france->reachableStations($initial) as $station){ |
|
echo "\t- ".$station."\n"; |
|
} |
|
|
|
echo "Atteignable depuis Londres :\n"; |
|
$initial = $tgv_france->getStation("Londres"); |
|
foreach($tgv_france->reachableStations($initial) as $station){ |
|
echo "\t- ".$station."\n"; |
|
} |
|
die(); |
|
|
|
echo "Peut-on aller de Lyon à Montpellier :\n"; |
|
$from = $tgv_france->getStation("Lyon"); |
|
$to = $tgv_france->getStation("Montpellier"); |
|
echo ($tgv_france->canGoFromTo($from, $to) ? "oui" : "non")."\n";//"yes" |
|
|
|
|
|
echo "Peut-on aller de Berlin à Montpellier :\n"; |
|
$from = $tgv_france->getStation("Berlin"); |
|
$to = $tgv_france->getStation("Montpellier"); |
|
echo ($tgv_france->canGoFromTo($from, $to) ? "oui" : "non")."\n";//"no" |
|
|
|
|
|
echo "Le plus court chemin pour aller de Calais à Toulouse est :\n"; |