蓝桥杯-地铁换乘

来源:互联网 发布:webpack压缩js 编辑:程序博客网 时间:2024/04/29 01:10
为解决交通难题,某城市修建了若干条交错的地铁线路,线路名及其所属站名如stations.txt所示。

线1
苹果园
....
四惠东

线2
西直门
车公庄
....
建国门

线4
....

其中第一行数据为地铁线名,接下来是该线的站名。
当遇到空行时,本线路站名结束。

下一行开始又是一条新线....直到数据结束。

如果多条线拥有同一个站名,表明:这些线间可以在该站换车。

为引导旅客合理利用线路资源,解决交通瓶颈问题,该城市制定了票价策略:

1. 每条线路可以单独购票,票价不等。
2. 允许购买某些两条可换乘的线路的联票。联票价格低于分别购票。

单线票价和联合票价如 price.txt 所示。

线1 180
.....
线13 114
线1,线2 350
线1,线10 390
.....

每行数据表示一种票价
线名与票价间用空格分开。如果是联票,线名间用逗号分开。
联票只能包含两条可换乘的线路。

现在的问题是:根据这些已知的数据,计算从A站到B站最小花费和可行的换乘方案。

比如,对于本题目给出的示例数据

如果用户输入:
五棵松,奥体中心

程序应该输出:
-(线1,线10)-线8 = 565

如果用户输入:
五棵松,霍营

程序应该输出:
-线1-(线4,线13) = 440

可以看出,用户输入的数据是:起始站,终到站,用逗号分开。
程序输出了购票方案,在括号中的表示联票,短横线(-)用来分开乘车次序。
等号后输出的是该方案的花费数值。

请编程解决上述问题。
注意:
1. 我们测试您的程序时,所用数据与题目中的示例数据不同,但格式完全一样。
2. 当多个方案有相同的最小花费,输出任意一个方案即可。

要求考生把所有类写在一个文件中。
调试好后,存入与考生文件夹下对应题号的“解答.txt”中即可。
相关的工程文件不要拷入。请不要使用package语句。

另外,源程序中只能出现JDK1.5中允许的语法或调用。不能使用1.6或更高版本。

解析:

1.先处理所有的站点,求出所有线路的交叉线路,将线路看成图的一个结点,任何两条线路如果彼此交叉,则这两个线路结点相连。

2.先确定开始站和结束站在哪条线路上,然后将问题转而求从某个结点到另一个结点的路径

3.遍历以上定义的图,可以得出所有符合条件的路径,然后对每一个路径求价钱(因为有联票,所以一条路径可能有多种价钱,如存在这样一条路径:线路1-线路2-线路3-线路4,如果线路2和线路3是可以联票的,则有"线路1-(线路2,线路3)-线路4"的情况出现)

4.每次对符合要求的路径求得对应的价钱,则和最小价钱对比,比其小则保留最少价钱的方案

备注:这道题实现的时候没有使用分支限界法,效率上打了折扣,如果用分支限界法来遍历线路图,可以提高不少性能

java代码如下:

import java.io.BufferedReader;import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.IOException;import java.io.InputStreamReader;import java.util.ArrayList;import java.util.HashMap;import java.util.Iterator;import java.util.List;import java.util.Map;import java.util.Scanner;public class js_04 {public static void main(String[] args) {Scanner scanner=new Scanner(System.in);String input=null;String[] tmp=null;while(scanner.hasNextLine()){input=scanner.nextLine();tmp=input.split(",");new js_04(tmp[0],tmp[1]);}}public js_04(String start,String end){//解析stations.txt文件,初始化站点信息initStations();//初始化线路相连信息initLines();//解析price.txt文件,初始化价格信息initPrice();input(start,end);startProcess();}//起始站集合private List<String> start=new ArrayList<String>();//终点站集合private List<String> end=new ArrayList<String>();//输入起始站和终点站public void input(String stationA,String stationB){//找到该站属于哪条线Iterator<String> it=stationsMap.keySet().iterator();String stations=null;String line=null;while(it.hasNext()){line=it.next();stations=stationsMap.get(line);if(stations.contains(stationA+",")){//添加到开始线路集合start.add(line);}if(stations.contains(stationB+",")){//添加到结束线路集合end.add(line);}}}//开始正式处理public void startProcess(){for(String st:start){for(String en:end){Line cuStart=lines.get(st);cuStart.isUse=true;process.add(cuStart);nfs(cuStart,lines.get(en));process.remove(cuStart);cuStart.isUse=false;}}//输入最终结果if(minPriceProcess!=null){System.out.print(minPriceProcess+" = ");System.out.println(minPrice);}else{System.out.println("不可达");}}//存储遍历过程private List<Line> process=new ArrayList<Line>(); public void nfs(Line startLine,Line endLine){//结束找到符合要求的路径if(startLine.equals(endLine)){calPrice();}else{//遍历所有的可连接节点for(Line line:startLine.connLines){//已经遍历过则跳过if(line.isUse)continue;line.isUse=true;process.add(line);nfs(line,endLine);process.remove(line);line.isUse=false;}}}//存储最少价钱private int minPrice=Integer.MAX_VALUE;private void calPrice(){length=process.size();String calProcss="";//存储过程cal(0,0,calProcss);}private int length;private String minPriceProcess;//lineIndex表示当前要处理的路线的下标public void cal(int lineIndex,int currPrice,String calProcess){if(lineIndex>=length){if(currPrice<minPrice){minPriceProcess=calProcess;minPrice=currPrice;}return;}if(lineIndex==length-1){Line line=process.get(lineIndex);currPrice+=line.price;if(currPrice<minPrice){minPrice=currPrice;minPriceProcess=calProcess+"-"+line;}return;}else{Line one=process.get(lineIndex);Line two=process.get(lineIndex+1);if(currPrice+one.price>=minPrice)return;cal(lineIndex+1,currPrice+one.price,calProcess+"-"+one);int connPrice=isConnection(one,two);if(connPrice!=-1){//可以相连,则考虑相连的情况if(currPrice+connPrice>=minPrice)return;cal(lineIndex+2,currPrice+connPrice,calProcess+"-("+one.name+","+two.name+")");}}}//判断两条线路是否联票,是则返回联票价钱,否则返回-1public int isConnection(Line one,Line two){String key=one.name+","+two.name;Integer value=connLines.get(key);if(value==null)return -1;return value;}//用于保存所有的线路信息,key为线路名,value为该线路下的所有站点private Map<String,String> stationsMap=new HashMap<String,String>();//存储线路的集合,通过路线名获得路线类对象private Map<String,Line> lines=new HashMap<String,Line>();public void initStations(){try {File file=new File("stations.txt");BufferedReader reader=new BufferedReader(new InputStreamReader(new FileInputStream(file)));StringBuilder value=new StringBuilder();String content=null;String key=null;boolean isHead=true;//是否是线路名while((content=reader.readLine())!=null){if("".equals(content)){//一条线路读取结束//将线路存储起来Line line=new Line();line.name=key;lines.put(key, line);stationsMap.put(key, value.toString());isHead=true;value.delete(0, value.length());}else{if(isHead){//第一个为线路名key=content;isHead=false;}else{value.append(content).append(",");}}}Line line=new Line();line.name=key;lines.put(key, line);stationsMap.put(key, value.toString());} catch (FileNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}//初始化线路连接情况public void initLines(){List<String> list=new ArrayList<String>(stationsMap.keySet());int length=list.size();for(int i=0;i<length;i++){for(int j=i+1;j<length;j++){//线路名process(list.get(i),list.get(j));}}}//处理所有交叉线路public void process(String l1,String l2){String line1=stationsMap.get(l1);String line2=stationsMap.get(l2);String[] strs=line1.split(",");for(String str:strs){if(line2.contains(str+",")){//如果两个路线有共同站点,说明交叉Line line01=lines.get(l1);Line line02=lines.get(l2);line01.connLines.add(line02);line02.connLines.add(line01);return;}}}//联票路线private Map<String,Integer> connLines=new HashMap<String,Integer>();//初始化价钱列表,获得联票信息public void initPrice(){try {File file=new File("price.txt");BufferedReader reader=new BufferedReader(new InputStreamReader(new FileInputStream(file)));String content=null;String[] keyValue=null;int price=0;while((content=reader.readLine())!=null){keyValue=content.split(" ");price=Integer.valueOf(keyValue[1]);if(keyValue[0].contains(",")){//联票connLines.put(keyValue[0], price);}else{//单条路线lines.get(keyValue[0]).price=price;}}} catch (FileNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}//自定义线路类class Line{//线路名public String name;//是否遍历过public boolean isUse;//和该路线交叉的路线List<Line> connLines=new ArrayList<Line>();//该路线的价钱public int price;@Overridepublic boolean equals(Object obj) {return this.name.equals(((Line)obj).name);}@Overridepublic String toString() {return this.name;}}}


原创粉丝点击