經典動態規劃:完全揹包問題
專案介紹
1.主要功能
提供一副地鐵線路圖,計算指定兩站之間最短(最少經過站數)乘車路線;輸出指定地鐵線路的所有站點。以北京地鐵為例,地鐵線路資訊儲存在data.txt中,格式如下:
地鐵線路總數 線路名1 站名1 站名2 站名3 ... 線路名2 站名1 站名2 站名3 ... 線路名3 站名1 站名2 站名3 ......
實現以下功能:
- 實現地鐵線路資訊圖的匯入
- 實現查詢功能,查詢指定地鐵線路之間的資訊
- 實現從出發地到目的地之間最短路徑規劃,並供使用者使用
2.實現語言
Java
3.實現演算法
Floyd演算法
通過一個圖的權值矩陣求出它的每兩點間的最短路徑矩陣。從圖的帶權鄰接矩陣A=[a(i,j)] n×n開始,遞迴地進行n次更新,即由矩陣D(0)=A,按一個公式,構造出矩陣D(1);又用同樣地公式由D(1)構造出D(2);……;最後又用同樣的公式由D(n-1)構造出矩陣D(n)。矩陣D(n)的i行j列元素便是i號頂點到j號頂點的最短路徑長度,稱D(n)為圖的距離矩陣,同時還可引入一個後繼節點矩陣path來記錄兩點間的最短路徑。
4.類職責劃分
- Floyd:Floyd演算法的具體實現。
- Main:讀入資料和啟動程式。
- Graph:用於儲存Floyd演算法中將會用到的圖的鄰接矩陣,即地鐵站點圖。
- ui:提供使用者互動介面。
- Line:線路類。
- Station:站點類。
5、核心程式碼
(1)Main類讀入資料驅動程式
package subway;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;public class Main {
public static void main(String[] args) {Graph G=new Graph();
String pathname = ".\\station.txt";
ArrayList<String> Information=new ArrayList<String>();
ArrayList<Line> allLines=new ArrayList<Line>();
try (
FileReader reader = new FileReader(pathname);
BufferedReader br = new BufferedReader(reader)
) {
String line;
while ((line = br.readLine()) != null) {
Information.add(line);
}
}
catch (IOException e) {
e.printStackTrace();
}
for(int i=0;i<Information.size();i+=2) {
Line lines =new Line();
String LineName=Information.get(i);
lines.setName(LineName);
String[] stations=Information.get(i+1).split("\\s+");
for(String s:stations) {
Station curStation=new Station();
curStation.setLine(LineName);
curStation.setName(s);
lines.getSubwayStation().add(curStation);
}
allLines.add(lines);
}
G.InitGraph(allLines);
new ui(G,allLines).setVisible(true);;
}
}
(2)station類儲存站點資訊
public class Station {
private String Line;
private String Name;
private boolean transfer = false;
public String getLine() {
return Line;
}
public void setLine(String line) {
Line = line;
}
public String getName() {
return Name;
}
public void setName(String name) {
Name = name;
}
public boolean equals(Station s){
if(this.Name.equals(s.getName()))
return true;
return false;
}
public boolean isTransfer() {
return transfer;
}
public void setTransfer(boolean transfer) {
this.transfer = transfer;
}
}
(3)Line類儲存線路資訊
package subway;
import java.util.ArrayList;
import java.util.List;public class Line {
private String Name;
private ArrayList<Station> SubwayStation=new ArrayList<Station>();
public String getName() {
return Name;
}
public void setName(String name) {
Name = name;
}
public ArrayList<Station> getSubwayStation() {
return SubwayStation;
}
public void setSubwayStation(ArrayList<Station> subwayStation) {
SubwayStation = subwayStation;
}
public Line PrintLine(String name,List<Line> allLines) {
for(Line s:allLines) {
if(name.equals(s.getName())) {
return s;
}
}
return null;
}
public boolean HaveStation(String name) {
for(Station s:SubwayStation) {
if(s.getName().equals(name))
return true;
}
return false;
}
}
(4)Floyd類 實現主要演算法
package subway;
import java.util.ArrayList;
import java.util.List;public class Floyd {
private List<Station> Stationlist = new ArrayList<Station>();
public ArrayList<String> getShortestPath(String s1,String s2,Graph G,List<Line> Lines) throws Exception{
int size=G.getMax();
int[][] path=new int[size][size];
int[][] d=G.getDist();
for(int i=0;i<size;i++)
for(int j=0;j<size;j++){
path[i][j]=j;
}
for(int k=0; k<size; k++){
for(int i=0; i<size; i++){
for(int j=0; j<size; j++) {
if(d[i][k]!=-1&&d[k][j]!=-1) {
if(d[i][j]>d[i][k]+d[k][j]) {
d[i][j]=d[i][k]+d[k][j];
path[i][j]=path[i][k];
}
}
}
}
}
int start=G.findStation(s1);
int end=G.findStation(s2);
if(start==-1)
throw new Exception("起點不存在");
if(end==-1)
throw new Exception("終點不存在");
if(start==end)
throw new Exception("起點和終點不能相同");
ArrayList<String> result=new ArrayList<String>();
if(start!=-1&&end!=-1) {
int count=0;
int temp=path[start][end];
Stationlist.add(G.getStations().get(start));
while(temp!=end ) {
Stationlist.add(G.getStations().get(temp));
temp=path[temp][end];
}
Stationlist.add(G.getStations().get(temp));
result.add(Integer.toString(Stationlist.size()));
result.add(Stationlist.get(0).getName());
for(int i=1;i<Stationlist.size()-1;i++) {
result.add(Stationlist.get(i).getName());
if(Stationlist.get(i).isTransfer()==true) {
String res=IsTransferLine(Stationlist.get(i-1).getName(),Stationlist.get(i).getName(),Stationlist.get(i+1).getName(),Lines);
if(res!=null)
result.add(res);
}
}
result.add(Stationlist.get(Stationlist.size()-1).getName());
}
return result;
}
public String IsTransferLine(String pre,String mid,String next,List<Line> allLines) {
String start=null;
String end=null;
for(Line s:allLines) {
if(s.HaveStation(pre)&&s.HaveStation(mid))
start=s.getName();
if(s.HaveStation(mid)&&s.HaveStation(next))
end=s.getName();
}
if(!start.equals(end))
return end;
return null;
}
}
(5)Graph類 構造鄰接矩陣
package subway;
import java.util.ArrayList;
import java.util.List;public class Graph {
private int [][] Dist =new int[500][500];
private int Max;
public List<Station> Stations = new ArrayList<Station>();
public void InitGraph(List<Line> Lines) {
for(int i=0;i<Lines.size();i++) {
List<Station> Stations=Lines.get(i).getSubwayStation();
for(int j=0;j<Stations.size();j++) {
int index=this.getIndex(Stations.get(j));
if(index==-1)
Stations.add(Stations.get(j));
else if(index!=-1) {
Stations.get(index).setTransfer(true);
Lines.get(i).getSubwayStation().get(j).setTransfer(true);
}
}
}
Max=Stations.size();
for(int i=0;i<Max;i++)
for(int j=0;j<Max;j++){
if(i==j)
Dist[i][j]=0;
else
Dist[i][j]=500;
}
for(Line line:Lines) {
List<Station> Stations=line.getSubwayStation();
for(int j=0;j<Stations.size()-1;j++) {
int start =this.getIndex(Stations.get(j));
int end =this.getIndex(Stations.get(j+1));
Dist[start][end]=1;
Dist[end][start]=1;
}
}
}
public int getIndex(Station s) {
for(int i=0;i<Stations.size();i++)
if(Stations.get(i).getName().equals(s.getName()))
return i;
return -1;
}
public int findStation(String name) {
for(int i=0;i<Stations.size();i++)
if(Stations.get(i).getName().equals(name))
return i;
return -1;
}
public int getMax() {
return Max;
}
public void setMax(int max) {
Max = max;
}
public int[][] getDist() {
return Dist;
}
public void setDist(int[][] dist) {
Dist = dist;
}
public List<Station> getStations() {
return Stations;
}
public void setStations(List<Station> stations) {
Stations = stations;
}
}
(6)ui類互動介面
package subway;
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.FlowLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.table.DefaultTableModel;
import subway.Floyd;
import subway.Graph;
import subway.Station;
import subway.Line;public class ui extends JDialog implements ActionListener {
private ArrayList<Line> allLines=new ArrayList<Line>();
private Graph G=new Graph();
private JPanel toolBar = new JPanel();
private JPanel workPane = new JPanel();
private JButton btnFindLine = new JButton("查詢線路");
private JButton btnFindWay = new JButton("查詢最短路徑");
private JLabel labelLine = new JLabel("線路號:");
private JLabel labelStart = new JLabel("起點:");
private JLabel labelEnd = new JLabel("終點:");
private JTextField edtLine = new JTextField(50);
private JTextField edtStart = new JTextField(50);
private JTextField edtEnd = new JTextField(50);
private JList<String> list=new JList();
private JScrollPane scrollPane=new JScrollPane(list);
private Object tblStationData[][];
DefaultTableModel tabStationModel=new DefaultTableModel();
private JTable dataTableStation=new JTable(tabStationModel);
private JScrollPane StationPane=new JScrollPane(this.dataTableStation);
public ui(Graph G,ArrayList<Line> Lines) {
this.allLines=Lines;
this.G=G;
workPane.setLayout(null);
workPane.setBounds(0,0,400,250);
btnFindLine.setBounds(10, 40, 160, 20);
workPane.add(btnFindLine);
btnFindWay.setBounds(300, 70, 160, 20);
workPane.add(btnFindWay);
labelLine.setBounds(10, 10, 60, 20);
workPane.add(labelLine);
edtLine.setBounds(70, 10, 100, 20);
workPane.add(edtLine);
labelStart.setBounds(300, 10, 60, 20);
workPane.add(labelStart);
edtStart.setBounds(360, 10, 100, 20);
workPane.add(edtStart);
labelEnd.setBounds(300, 40, 60, 20);
workPane.add(labelEnd);
edtEnd.setBounds(360, 40, 100, 20);
workPane.add(edtEnd);
scrollPane.setBounds(10,100,160,300);
workPane.add(scrollPane);
StationPane.setBounds(300,100,160,300);
workPane.add(StationPane);
this.getContentPane().add(workPane, BorderLayout.CENTER);
this.setSize(600, 500);
double width = Toolkit.getDefaultToolkit().getScreenSize().getWidth();
double height = Toolkit.getDefaultToolkit().getScreenSize().getHeight();
this.setLocation((int) (width - this.getWidth()) / 2,
(int) (height - this.getHeight()) / 2);this.validate();
this.btnFindLine.addActionListener(this);
this.btnFindWay.addActionListener(this);
}
public void actionPerformed(ActionEvent e) {
if(e.getSource()==this.btnFindLine) {
String LineName=this.edtLine.getText();
try {
Line result=new Line().PrintLine(LineName, allLines);
if(result==null) throw new Exception("線路不存在");
String [] stations= new String[result.getSubwayStation().size()];
for(int i=0;i<result.getSubwayStation().size();i++) {
stations[i]=result.getSubwayStation().get(i).getName();
}
this.list.setListData(stations);
}
catch (Exception e1) {
JOptionPane.showMessageDialog(null, e1.getMessage(), "錯誤",JOptionPane.ERROR_MESSAGE);
return;
}
}
else if(e.getSource()==this.btnFindWay){
String start=this.edtStart.getText();
String end=this.edtEnd.getText();
try {
ArrayList<String> result=new Floyd().getShortestPath(start, end, G, allLines);
tblStationData = new Object[result.size()][1];
for(int i=0;i<result.size();i++) {
tblStationData[i][0]=result.get(i);
}
Object[] msg= {"最短路徑"};
tabStationModel.setDataVector(tblStationData,msg);
this.dataTableStation.validate();
this.dataTableStation.repaint();
} catch (Exception e1) {
JOptionPane.showMessageDialog(null, e1.getMessage(), "錯誤",JOptionPane.ERROR_MESSAGE);
return;
}
}
}
}
6、測試樣例
(1)輸入站點不正確:
(2)起點終點相同
(3)正常線路
(4)輸出線路
7、總結
本次實踐發現自己對java還是有諸多問題,各種資料結構使用的並不熟練。除了對自身程式碼能力的瞭解,也對軟體工程有了更深的瞭解從需求到實現,工程的規劃都有了更深的理解。
本次實驗已上傳git,https://github.com/hyrlzy666/subway