计应193 第二组 许颖然 地铁收费系统
计划:
明确需求和其他相关因素,估计每个阶段的时间成本
需求分析:
参考原文链接题目及需求分析
起始站到终点站之间有效最短路径
起始站到终点站两点经过的站点数
具体设计:
首先将北京市地铁规划图存储到文件中并读取,
然后使用迪杰斯特拉算法求出最短路径,并将结果展示,
最终根据最短路径来计算花费
具体编码和代码规范:
package Demo01; import java.io.*; import java.util.*; public class SubWay { 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 SubWay(tmp[0],tmp[1]); } } public SubWay(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+")"); } } } //判断两条线路是否联票,是则返回联票价钱,否则返回-1 public 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("C:\\Users\\dell\\Desktop\\softwarework\\src\\Demo01\\station.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 block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.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("C:\\Users\\dell\\Desktop\\softwarework\\src\\Demo01\\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 block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } //自定义线路类 class Line{ //线路名 public String name; //是否遍历过 public boolean isUse; //和该路线交叉的路线 List<Line> connLines=new ArrayList<Line>(); //该路线的价钱 public int price; @Override public boolean equals(Object obj) { return this.name.equals(((Line)obj).name); } @Override public String toString() { return this.name; } }
代码复审:
首先使用debug一步一步的检查运行,对出现的错误进行修改
然后将重复的代码抽取成一个方法,减少代码的长度,增加可阅读性
总结:
运用结对编程和其他小伙伴合作完成的部分代码,由于基础薄弱,知识能力有限,完成项目花费很长时间;同时让我明白结对的重要性;学习了新的算法,收获了一些学习经验。