今日分資料結構作業:圖的簡單操作
阿新 • • 發佈:2018-11-11
先上實驗報告:
還是比較簡單的。
但是開始沒有了解過圖的遍歷,也不知道怎麼遍歷。
其實也很簡單,安利個視訊:https://www.bilibili.com/video/av18586085?from=search&seid=6600959381110331126
講的比較詳細。
最小生成樹吧,身為一個ACMer,這麼簡單裸的板子當然好寫了。
我用的prim寫的,不過沒有堆優化。
但是我中間加了個東西,列印建邊過程,kruskal加這個東西應該比較簡單吧。
prim還是需要思考一下的。
下面程式碼那個註釋圖的樣子,文字有點不太正。
這樣的。
2333
程式碼:
import java.util.*; public class Main2 { public static void main(String[] args) { Graph g=new Graph(5); g.addEdge(1, 2,1); g.addEdge(4, 2,10); g.addEdge(1, 3,1); g.addEdge(1, 5,10); g.addEdge(3, 5,2); //這個圖的樣子大概就是 /* 1 * /|\ * 1 / | \10 * / 1| \ * 4---2 3---5 * 10 2 */ System.out.println("廣搜結果:"); g.bfs(); System.out.println("深搜結果:"); g.dfs(); g.prim(); } } class Graph{ private int map[][]; //臨界矩陣表示圖 private int n; //表示節點個數 private boolean used[]; //表示用過的邊 public Graph() {} public Graph(int n) { this.n=n; map=new int[n+1][n+1]; used=new boolean[n+1]; } //=======================================dfs遍歷圖,但是如果圖不連通的話可能遍歷不了。 public void dfs() { for(int i=1;i<=n;i++) used[i]=false; dfs(1); System.out.println(); } private void dfs(int i) { used[i]=true; System.out.print(i+" "); for(int j=1;j<=n;j++) { if(map[i][j]!=0&&!used[j]) { dfs(j); } } } //========================================bfs遍歷圖 public void bfs() { for(int i=1;i<=n;i++) used[i]=false; LinkedList<Integer> list=new LinkedList<Integer>(); list.offer(1); used[1]=true; while(!list.isEmpty()) { int t=list.poll(); System.out.print(t+" "); for(int i=1;i<=n;i++) { if(map[t][i]!=0&&!used[i]) { used[i]=true; list.offer(i); } } } System.out.println(); } public void addEdge(int a,int b) { map[a][b]=map[b][a]=1; } public void addEdge(int a,int b,int c) { map[a][b]=map[b][a]=c; } /* * prim演算法其實可以通過優先佇列優化到nlogn,但是懶得用了 * 如果套板子的話感覺太無聊 * 然後就想了個主意,不如在計算值的同時加一個判斷,中間列印生成樹的過程。 * 然後和裸的板子不同,加了個from陣列,記錄上一個點到這的最小點,然後就完成了這個重大任務。 * 太晚了,應該沒有bug * 加這個小東西,完全是一時興起(sangxinbingkuang) * 耽誤了不少時間,用了debug * 其實prim演算法挺好的,時間複雜度可以優化到vlogv * 而kruskal演算法的複雜度是eloge * 空間複雜度上應該就是kruskal比較佔優勢了。各有好處吧。 * 但是感覺還是prim演算法用的比較多 * 身為一個ACMer,表示我半年前就學會最小生成樹了2333 */ public int prim() { int from[]=new int[n+1]; from[1]=1; int ans=0; for(int i=1;i<=n;i++) used[i]=false; while(true) { int t=-1; //確定一個點,如果這個點的from-to 的value最小,那就優先選擇這個點。 for(int i=1;i<=n;i++) { if(!used[i]&&(t==-1||(map[from[i]][i]<map[from[t]][t]&&from[i]!=0))) t=i; } //如果更新點後t依然是-2,說明沒有點更新了。 if(t==-1) break; used[t]=true; if(t!=1) System.out.println(from[t]+"-->"+t+"="+map[from[t]][t]); ans+=map[from[t]][t]; //更新一個點後,沒用過的節點全部都更新一下from。 for(int i=1;i<=n;i++) { if(!used[i]&&(from[i]==0||map[t][i]<map[from[i]][i])&&map[t][i]!=0) { from[i]=t; } } } System.out.println("最小价值位:"+ans); return ans; } }