Which Way Do I Go?
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 394 | Accepted: 66 |
Description
You've decided that the time is right for the next Internet map startup. Your inspiration for this venture is your directionally impaired spouse, who doesn't care for the shortest or quickest routes generated by current online map systems-instead, easier is better.
The backbone of your operation is, of course, your algorithm for calculating directions. Your algorithm must accept the map from your massive database of the entire country and produce the best route that meets the customer's query. Queries consist of an origin, destination, and the optimization goal, which can be for the shortest route, fastest route, or route with the fewest turns. You are guaranteed that there will be a path between source and destination for any query asked.
The backbone of your operation is, of course, your algorithm for calculating directions. Your algorithm must accept the map from your massive database of the entire country and produce the best route that meets the customer's query. Queries consist of an origin, destination, and the optimization goal, which can be for the shortest route, fastest route, or route with the fewest turns. You are guaranteed that there will be a path between source and destination for any query asked.
Input
There are three sections in the input file, the first lists the cities, the second lists the roads, and the third lists the queries.
The first line of input is the number of cities, c, followed by c lines each containing the name of a city. There is no whitespace in a city name.
The next line is the number of roads, r, followed by r lines describing a road. Each road description has the following form:
< RoadName > < CityA > < ABDistance > < ABTime > < CityB > [< BCDist > < BCTime > < CityC > [...]]
There is no whitespace in a road's name. Roads may pass through any number of cities. The cities appear in the order the road passes through them. No road passes through the same city multiple times. Roads are bidirectional. The distance and time (both real numbers) it takes to follow a road between each pair of cities is the distance and time listed between those two names.When following a road between multiple cities (A to C, for example), the distance and time is cumulative for all steps along the path.
The remainder of the lines in the file each list one query. Queries are of the form:
< querytype > < origin > < destination >
Querytype is one of time, distance, or turns and the origin and destination are the names of cities.
The queries end at end-of-file.
The first line of input is the number of cities, c, followed by c lines each containing the name of a city. There is no whitespace in a city name.
The next line is the number of roads, r, followed by r lines describing a road. Each road description has the following form:
< RoadName > < CityA > < ABDistance > < ABTime > < CityB > [< BCDist > < BCTime > < CityC > [...]]
There is no whitespace in a road's name. Roads may pass through any number of cities. The cities appear in the order the road passes through them. No road passes through the same city multiple times. Roads are bidirectional. The distance and time (both real numbers) it takes to follow a road between each pair of cities is the distance and time listed between those two names.When following a road between multiple cities (A to C, for example), the distance and time is cumulative for all steps along the path.
The remainder of the lines in the file each list one query. Queries are of the form:
< querytype > < origin > < destination >
Querytype is one of time, distance, or turns and the origin and destination are the names of cities.
The queries end at end-of-file.
Output
For each query, your output will begin with a line:
from < origin >
Each following line will be of the form:
< roadName > to < cityname >
which lists the road to turn onto from the previous city, and the city to take that road to. If a single road is followed between multiple cities, only the final city reached on that road before turning onto another road is listed. The final city listed will be the destination city.
from < origin >
Each following line will be of the form:
< roadName > to < cityname >
which lists the road to turn onto from the previous city, and the city to take that road to. If a single road is followed between multiple cities, only the final city reached on that road before turning onto another road is listed. The final city listed will be the destination city.
Sample Input
5 Chicago DesMoines OklahomaCity Dallas LosAngeles 4 I80 Chicago 300 4 DesMoines I35 DesMoines 550 7.3 OklahomaCity 205 3 Dallas I40 OklahomaCity 1330 20.5 LosAngeles Rt66 Chicago 2448 46 LosAngeles time Chicago LosAngeles turns Chicago LosAngeles
Sample Output
from Chicago I80 to DesMoines I35 to OklahomaCity I40 to LosAngeles from Chicago Rt66 to LosAngeles
Solution:
package id1582;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.LinkedList;
public class WhichWayDoIGo {
BufferedReader in = null;
String[] cities = null;
Graph graph = null;
final boolean DEBUG = false;
int cityNum = 0;
int routesNum = 0;
public WhichWayDoIGo() {
in = new BufferedReader(new InputStreamReader(System.in));
}
private void start() throws NumberFormatException, IOException{
String str = null;
String[] strArry = null;
LinkedList<Edge> solution = null;
Graph duplicate_graph = null;
cityNum = Integer.parseInt(in.readLine());
cities = new String[cityNum];
for(int i = 0; i < cityNum; i++)
cities[i] = in.readLine();
routesNum = Integer.parseInt(in.readLine());
graph = new Graph(routesNum);
for(int i = 0; i < routesNum; i++){
graph.addNode(in.readLine());
}
if(DEBUG) graph.printGraph();
str = in.readLine();
while(!str.equals("") || str != null){
duplicate_graph = new Graph(graph);
strArry = str.split(" ");
solution = search4solution(strArry[0],strArry[1],strArry[2],duplicate_graph);
printSolution(solution);
str = in.readLine();
solution.clear();
}
}
private void printSolution(LinkedList<Edge> solution){
Edge edge = null;
if(solution == null){
System.out.println("Solution is null");
System.exit(0);
}
else
edge = solution.poll();
System.out.println("from " + edge.srcName);
System.out.println(edge.routeName + " to " + edge.targetName);
while(!solution.isEmpty()){
edge = solution.poll();
if(edge != null) System.out.println(edge.routeName + " to " + edge.targetName);
}
}
private LinkedList<Edge> search4solution(String format, String orig, String dest, Graph graph){
EdgeList originEdgelist = null;
LinkedList<Edge> bestSolution = null;
LinkedList<LinkedList<Edge>> paths = null;
for(int i =0; i < graph.adjList.size(); i++)
if(graph.adjList.get(i).OriginName.equals(orig)){
originEdgelist = graph.adjList.remove(i);
break;
}
if(originEdgelist == null)
System.out.println("Can not find this originCity");
paths = getAvailablePaths(originEdgelist,orig,dest,graph);
bestSolution = findBestSolution(paths,format);
if (bestSolution.isEmpty()) {
System.out.println("bestSolution is empty");
System.exit(0);
}
return bestSolution;
}
private LinkedList<Edge> findBestSolution(LinkedList<LinkedList<Edge>> listSolution, String format){
int cheapestPathIndex = Integer.MAX_VALUE;
float cheapstCost = Float.MAX_VALUE;
float cost = 0;
for(int i = 0; i < listSolution.size(); i++){
if(DEBUG)
System.out.println("Get in another path");
if(DEBUG){
for(int j = 0; j < listSolution.get(i).size(); j++){
if(listSolution.get(i).get(j) != null){
listSolution.get(i).get(j).print();
System.out.println("");
} else
System.out.println("Edge is null");
}
}
if(format.equals("time"))
cost = calculateTimeCost(listSolution.get(i),0);
else if(format.equals("turns"))
cost = calculateTurnsCost(listSolution.get(i),0);
else if(format.equals("distance"))
cost = calculateDistanceCost(listSolution.get(i),0);
if(cost < cheapstCost) {
if(DEBUG)
System.out.println("Less than the cheapstCost index changed to " + i);
cheapstCost = cost;
cheapestPathIndex = i;
}
}
if(DEBUG)
System.out.println("\nThis path cost is " + cheapstCost);
return listSolution.get(cheapestPathIndex);
}
private float calculateDistanceCost(LinkedList<Edge> path, int index){
Edge edge = null;
if(index < path.size()){
edge = path.get(index);
if(edge == null) {
System.out.println("Edge is null at calculateDistanceCost function");
return calculateDistanceCost(path, index + 1);
}
return (edge.distance + calculateDistanceCost(path, index + 1));
} else
return 0;
}
private float calculateTurnsCost(LinkedList<Edge> path, int index){
Edge edge = null;
if(index < path.size()){
edge = path.get(index);
if(edge == null) return calculateTurnsCost(path, index + 1);
return (1 + calculateTurnsCost(path, index + 1));
} else
return 0;
}
private float calculateTimeCost(LinkedList<Edge> path, int index){
Edge edge = null;
if(index < path.size()){
edge = path.get(index);
if(edge == null) return calculateTimeCost(path, index + 1);
return (edge.timeCost + calculateTimeCost(path, index + 1));
} else
return 0;
}
private LinkedList<LinkedList<Edge>> getAvailablePaths(EdgeList origEdgelist,
String orig,String dest,Graph graph){
// System.out.println("Go in TimeOptimized Function");
Solution solution = new Solution();
// put origin city name to path
solution.parentSolution = null;
Solution subSolutions = null;
LinkedList<Solution> listSolutions = new LinkedList<Solution>();
// distribute each edge connectted with origin to helper function
for(int i = 0; i < origEdgelist.edgeList.size(); i++){
subSolutions = searchPathWithTimeOptimized_helper(origEdgelist.edgeList.get(i),dest,graph);
// if exists a path from this edge to destination, then subSolutions is not null
if(subSolutions != null){
listSolutions.offer(subSolutions);
}
}
if (listSolutions.isEmpty()) {
System.out.println("listSolutions is empty");
System.exit(0);
}
// put all sub paths to path
solution.subSolutions = listSolutions;
return getAvaiblPaths(solution);
}
private LinkedList<LinkedList<Edge>> getAvaiblPaths(Solution solutions){
LinkedList<Edge> listEdge = new LinkedList<Edge>();
@SuppressWarnings("unchecked")
Edge parentEdge = solutions.parentSolution;
LinkedList<Solution> subSolutions = solutions.subSolutions;
LinkedList<LinkedList<Edge>> listSolution = new LinkedList<LinkedList<Edge>>();
while(!subSolutions.isEmpty())
getAvaiblPaths_helper(parentEdge,listEdge,subSolutions.poll(),listSolution);
return listSolution;
}
// parentEdge is parennt Edge, parent_listEdge records the path till now, solution is current node, listSolution cllect all the parent_listEdge at last
private void getAvaiblPaths_helper(Edge parentEdge,LinkedList<Edge> parent_listEdge,Solution solution, LinkedList<LinkedList<Edge>> listSolution){
@SuppressWarnings("unchecked")
LinkedList<Edge> listEdge = (LinkedList<Edge>) parent_listEdge.clone();
if(parentEdge != null)
listEdge.offer(parentEdge);
Edge edge = solution.parentSolution;
LinkedList<Solution> subSolutions = solution.subSolutions;
if(subSolutions == null){
if(edge != null)
listEdge.offer(edge);
listSolution.offer(listEdge);
return;
}
while(!subSolutions.isEmpty()){
getAvaiblPaths_helper(edge,listEdge,subSolutions.poll(),listSolution);
}
}
private Solution searchPathWithTimeOptimized_helper(Edge edge, String dest, Graph graph ){
EdgeList originEdgelist = null;
Solution solutionHelper = null;
Solution solutions = new Solution();
LinkedList<Solution> listSubSolutions = new LinkedList<Solution>();
String src = edge.targetName;
solutions.parentSolution = edge;
// System.out.println("Get in searchPathWithTimeOptimized_helper");
// edge.print();
// System.out.println("");
if(src.equals(dest)){
return solutions;
}
Edge subEdge = null;
for(int i = 0; i < graph.adjList.size(); i++)
if(graph.adjList.get(i).OriginName.equals(src)){
if(DEBUG) System.out.println("Found city " + src + "," + src + "'s edgeList was removed ");
originEdgelist = graph.adjList.remove(i);
break;
}
if(originEdgelist == null) {
return null;
}
while(!originEdgelist.edgeList.isEmpty()){
subEdge = originEdgelist.edgeList.poll();
solutionHelper = searchPathWithTimeOptimized_helper(subEdge,dest,graph);
if(solutionHelper != null){
listSubSolutions.offer(solutionHelper);
}
}
if(listSubSolutions.isEmpty()) return null;
else {
solutions.subSolutions = listSubSolutions;
return solutions;
}
}
public static void main(String[] args){
try {
new WhichWayDoIGo().start();
} catch (NumberFormatException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private class Graph{
int nodeNum = 0;
LinkedList<EdgeList> adjList = null;
public Graph(int nodeNum){
this.nodeNum = nodeNum;
this.adjList = new LinkedList<EdgeList>();
}
public Graph(Graph graph){
this.nodeNum = graph.nodeNum;
this.adjList = new LinkedList<EdgeList>();
for(int i =0; i < graph.adjList.size(); i++)
this.adjList.offer(new EdgeList(graph.adjList.get(i)));
}
public void printGraph(){
for(int i = 0; i < this.adjList.size(); i++)
this.adjList.get(i).print();
}
private void addNode(String str){
EdgeList edgelist = null;
String[] strArry = str.split(" ");
int nodesNum = (strArry.length - 2) / 3 + 1;
for(int i = 0; i < nodesNum; i++){
if(hasThisOriginName(strArry[i * 3 + 1],adjList)) {
edgelist = popThisEdgeList(strArry[i * 3 + 1],adjList);
adjList.offer(addnewedges(i * 3 + 1,nodesNum,strArry,edgelist));
}else{
EdgeList edgelist1 = new EdgeList(strArry[i * 3 + 1]);
edgelist1 = addnewedges(i * 3 + 1,nodesNum,strArry,edgelist1);
adjList.offer(edgelist1);
}
}
}
private EdgeList addnewedges(int origIndex,int nodesNum, String[] strArry, EdgeList edgelist){
if(origIndex == strArry.length - 1){
try{
edgelist = addEdge(strArry[0],strArry[origIndex],strArry[origIndex - 2],strArry[origIndex - 1],strArry[origIndex - 3],edgelist);
}catch(Exception e){
System.err.println("err here " + e.getMessage());
System.exit(0);
}
}
else if(origIndex != 1){
edgelist = addEdge(strArry[0],strArry[origIndex],strArry[origIndex + 1],strArry[origIndex + 2],strArry[origIndex + 3],edgelist);
edgelist = addEdge(strArry[0],strArry[origIndex],strArry[origIndex - 2],strArry[origIndex - 1],strArry[origIndex - 3],edgelist);
}else{
edgelist = addEdge(strArry[0],strArry[origIndex],strArry[origIndex + 1],strArry[origIndex + 2],strArry[origIndex + 3],edgelist);
}
return edgelist;
}
private EdgeList addEdge(String routeName,String srcName,String distStr, String timeStr, String Destination, EdgeList edgelist){
Edge edge = new Edge(routeName,srcName,distStr,timeStr,Destination);
edgelist.edgeList.offer(edge);
return edgelist;
}
// return the EdgeList whose originName is originName;
private EdgeList popThisEdgeList(String originName, LinkedList<EdgeList> adjList){
EdgeList edglist = null;
for(int i = 0; i < adjList.size(); i++){
if(adjList.get(i).OriginName.equals(originName))
return adjList.remove(i);
}
return edglist;
}
// returns true if origName exists in the adjList
private boolean hasThisOriginName(String origName,LinkedList<EdgeList> adjList){
for(int i = 0; i < adjList.size(); i++){
if(origName.equals(adjList.get(i).OriginName))
return true;
}
return false;
}
}
private class Solution {
Edge parentSolution = null;
LinkedList<Solution> subSolutions = null;
public Solution(Edge parentSolution, LinkedList<Solution> subSolutions){
this.parentSolution = parentSolution;
this.subSolutions = subSolutions;
}
public Solution(Edge parentSolution){
this.parentSolution = parentSolution;
}
public Solution(LinkedList<Solution> subSolutions){
this.subSolutions = subSolutions;
}
public Solution(){
}
}
private class EdgeList{
LinkedList<Edge> edgeList = null;
String OriginName = null;
public EdgeList(String OriginName){
this.OriginName = OriginName;
edgeList = new LinkedList<Edge>();
}
public EdgeList(EdgeList edgelist){
this.OriginName= edgelist.OriginName;
this.edgeList = new LinkedList<Edge>();
for(int i = 0; i < edgelist.edgeList.size(); i++)
this.edgeList.offer(new Edge(edgelist.edgeList.get(i)));
}
public void print(){
System.out.print("adjList: From: " + this.OriginName + " To: ");
for(int j = 0; j < this.edgeList.size(); j++){
this.edgeList.get(j).print();
System.out.print(", ");
}
System.out.println("");
}
}
private class Edge{
String targetName = null;
String srcName = null;
String routeName = null;
int distance = 0;
float timeCost = 0;
public Edge(Edge edge){
this.targetName = edge.targetName;
this.srcName = edge.srcName;
this.routeName = edge.routeName;
this.distance = edge.distance;
this.timeCost = edge.timeCost;
}
/*public Edge(String srcName, String targetName){
this.srcName = srcName;
this.targetName = targetName;
this.routeName = "No Name";
}*/
public Edge(String routeName,String srcName,String distanceStr, String timeStr, String targetName){
try{
this.routeName = routeName;
this.srcName = srcName;
this.distance = Integer.parseInt(distanceStr);
this.timeCost = Float.parseFloat(timeStr);
this.targetName = targetName;
} catch (Exception e){
System.err.println("new Edge: " + routeName + " " + distanceStr + " " + timeStr + " " + targetName + '\n' + e.getMessage());
System.exit(0);
}
}
public void print(){
System.out.print(" " + srcName + " " + targetName);
}
}
}