1. 程式人生 > >有向圖最短路Dijkstras演算法過程動態演示

有向圖最短路Dijkstras演算法過程動態演示

/**********************************************    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;
	}
}