有向圖最短路Dijkstras演算法過程動態演示
阿新 • • 發佈:2018-12-24
/********************************************** 2015.1.9---1.12 by yzk ************************************************************************/
<pre name="code" class="java">import java.util.*; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.geom.GeneralPath; import java.lang.Thread; import java.lang.Runnable; public class init { public static void main(String[] args) throws Exception { //Graph g2=new Graph(); // login my=new login(); Graph g1=new Graph(); // Thread my=new Thread(g2); // my.start(); //g1.gos(); // g2.start(); // g1.readin(); // g1.play(); //g1.setVisible(true); } }
import java.util.*; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.geom.GeneralPath; import java.lang.Thread; import java.lang.Runnable; public class Graph extends JFrame { public static int wait=0; JButton stop= new JButton("STOP"); //暫停按鈕 JButton go= new JButton("GO"); //開始按鈕 public Graph ()throws Exception { setBounds(0, 0, 1380, 800); //設定大小 this.setBackground(Color.WHITE); //背景色 this.setTitle("基於OSPF協議的有向圖最短路Dijkstra演算法動態過程演示系統"); this.setLayout(null); JLabel lblNewLabel = new JLabel("<html>最<br>短<br>路<br>算<br>法<br>動<br>態<br>過<br>程"); lblNewLabel.setFont(new Font("長城行楷體", Font.BOLD, 60)); //標籤相關設定 lblNewLabel.setVerticalAlignment(SwingConstants.TOP); //置頂 lblNewLabel.setForeground(new Color(0, 0, 0)); lblNewLabel. setBounds(20,0,90,800); add(lblNewLabel); Gra temp=new Gra(); // 建圖 temp.setBounds(90, 0, 1290, 800); temp.readin(); add(temp); this.setVisible(true); temp.play(); //演示演算法過程 } } class Gra extends JPanel { int [] head; //鏈式前向星存圖 int [][] edge; int nume; int maxn; //頂點數 int maxm; //邊數 int inf=0x3f3f3f3f; //無窮大 int ss,tt; //源匯點 int change; //開關量 int []mark; //最短路的標記 int []dis; //距離 int []got; //是否需要閃爍標記(正在被更新) points [] dian; //點類 int [][] lines; public Gra() //初始化建構函式 { head=new int [1005]; edge=new int [5000][3]; lines= new int [10000][5]; dis=new int [1006]; got=new int [5000]; mark=new int [1006]; nume=0; change=0; for(int i=0;i<1000;i++) { head[i]=-1;dis[i]=inf;got[i]=mark[i]=0; } } public void adde(int i,int j,int w) //新增一條有向邊 { edge[nume][0]=j;edge[nume][1]=head[i];head[i]=nume; edge[nume++][2]=w; } void magic0() //延時重畫函式 { try { Thread.sleep(300); } catch (InterruptedException e) { e.printStackTrace(); } this.repaint(); } void magic() //閃爍控制函式 { int cur=5; //變換次數 while(cur!=0) { change=1; //燈開 magic0(); change=0; //燈滅 magic0(); cur--; //System.out.println(cur); } } public void readin ()throws Exception //讀入圖函式 { java.io.File file= new java.io.File("scores.txt"); //讀入資料 // java.io.File file= new java.io.File("scores2.txt"); //讀入資料 // java.io.File file= new java.io.File("radscores.txt"); Scanner input =new Scanner(file); while(input.hasNext()) { maxn=input.nextInt(); maxm=input.nextInt(); int from,to,w; for(int i=0;i<maxm;i++) { from=input.nextInt(); to=input.nextInt(); w=input.nextInt(); adde(from,to,w); } ss=input.nextInt(); tt=input.nextInt(); dis[ss]=0; } input.close(); java.io.File file2 = new java.io.File("points.txt"); //讀入座標點 // java.io.File file2 = new java.io.File("points2.txt"); //java.io.File file2= new java.io.File("radpoints.txt"); Scanner input2 =new Scanner(file2); dian =new points [maxn+1]; for(int i=1;i<=maxn;i++) { dian[i]=new points(input2.nextInt(),input2.nextInt()); } } public void play() //Dijkstra演算法 { int marks=1; while(marks==1) { int mins=inf; marks=0; int cur=0; for(int i=1;i<=maxn;i++) { if(mark[i]==0&&dis[i]<mins) { mins=dis[i]; cur=i; marks=1; } } got[cur]=1; //點需要閃 magic(); got[cur]=0; //關閉該點,之後就不再閃 mark[cur]=1; for(int j=head[cur];j!=-1;j=edge[j][1]) { int to=edge[j][0]; if(mark[to]==0&&dis[to]>dis[cur]+edge[j][2]) { dis[to]=dis[cur]+edge[j][2]; lines[j][0]=1; //該線已變色 lines[j][1]=1; //該線需要閃 magic(); lines[j][1]=0; //無需再閃 } } } } protected void paintComponent( Graphics g) //畫圖函式 { super.paintComponent(g); //清屏 g.setColor(Color.green); Font font = new Font("Arial", Font.BOLD, 25); //字型大小 g.setFont(font); for(int i=1;i<=maxn;i++) { if(got[i]==1) //該點在閃 { if(change==1) //燈開 g.setColor(Color.red); else g.setColor(Color.GREEN); //燈滅 } else { if(mark[i]==1) //該點已變 g.setColor(Color.red); else g.setColor(Color.GREEN); } g.fillOval(dian[i].x, dian[i].y, 50, 50); String ts; if(dis[i]==inf) ts="+∞"; else ts=new String().valueOf(dis[i]); g.drawString(ts,dian[i].x,dian[i].y); } g.setColor(Color.GRAY); for(int i=1;i<=maxn;i++) { for(int j=head[i];j!=-1;j=edge[j][1]) { if(lines[j][1]==1) //需要閃爍 { if(change==1) g.setColor(Color.BLUE); else g.setColor(Color.GRAY); } else { if(lines[j][0]==1) //已經變色 g.setColor(Color.BLUE); else g.setColor(Color.GRAY); } // g.drawString(new String().valueOf(dis[edge[j][2]]),dian[i].x,dian[i].y); Graphics2D g2= (Graphics2D)g; drawAL(dian[i].x+25,dian[i].y+25, dian[edge[j][0]].x+25, dian[edge[j][0]].y+25,g2); //劃邊 // g.drawLine(dian[i].x+25,dian[i].y+25, dian[edge[j][0]].x+25, dian[edge[j][0]].y+25); int mx=(dian[i].x+25+dian[edge[j][0]].x+25)/2; int my=(dian[i].y+25+dian[edge[j][0]].y+25)/2; g.drawString(new String().valueOf(edge[j][2]), mx,my); } } } public static void drawAL(int sx, int sy, int ex, int ey, Graphics2D g2) { double H = 20; // 箭頭高度 double L = 6; // 底邊的一半 int x3,y3,x4,y4; double awrad = Math.atan(L / H); // 箭頭角度 double arraow_len = Math.sqrt(L * L + H * H); // 箭頭的長度 double[] arrXY_1 = rotateVec(ex - sx, ey - sy, awrad, true, arraow_len); double[] arrXY_2 = rotateVec(ex - sx, ey - sy, -awrad, true, arraow_len); double x_3 = ex - arrXY_1[0]; // (x3,y3)是第一端點 double y_3 = ey - arrXY_1[1]; double x_4 = ex - arrXY_2[0]; // (x4,y4)是第二端點 double y_4 = ey - arrXY_2[1]; Double X3 = new Double(x_3); x3 = X3.intValue(); Double Y3 = new Double(y_3); y3 = Y3.intValue(); Double X4 = new Double(x_4); x4 = X4.intValue(); Double Y4 = new Double(y_4); y4 = Y4.intValue(); g2.drawLine(sx, sy, ex, ey); // 畫線 GeneralPath triangle = new GeneralPath(); triangle.moveTo(ex, ey); triangle.lineTo(x3, y3); triangle.lineTo(x4, y4); triangle.closePath(); g2.fill(triangle); //實心箭頭 //g2.draw(triangle); //非實心箭頭 } public static double[] rotateVec(int px, int py, double ang, // 計算箭頭的左右倆的點 boolean isChLen, double newLen) { double mathstr[] = new double[2]; // 引數含義分別是x分量、y分量、旋轉角、是否改變長度、新長度 double vx = px * Math.cos(ang) - py * Math.sin(ang); double vy = px * Math.sin(ang) + py * Math.cos(ang); if (isChLen) { double d = Math.sqrt(vx * vx + vy * vy); vx = vx / d * newLen; vy = vy / d * newLen; mathstr[0] = vx; mathstr[1] = vy; } return mathstr; } } class points { int x,y; points(){}; points(int x,int y) { this.x=x; this.y=y; } }