计应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一步一步的检查运行,对出现的错误进行修改

  然后将重复的代码抽取成一个方法,减少代码的长度,增加可阅读性

总结:

        运用结对编程和其他小伙伴合作完成的部分代码,由于基础薄弱,知识能力有限,完成项目花费很长时间;同时让我明白结对的重要性;学习了新的算法,收获了一些学习经验。

 

posted @ 2021-04-10 20:39  草莓曲奇饼  阅读(72)  评论(0编辑  收藏  举报