1. 程式人生 > 實用技巧 >經典動態規劃:完全揹包問題

經典動態規劃:完全揹包問題

專案介紹

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