日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

陈越《数据结构》第六讲 图(上)

發布時間:2024/1/18 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 陈越《数据结构》第六讲 图(上) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

6.1 什么是圖


6.1.1 定義


  • 圖示表示“多對多”的關系(樹與線性表都可以認為是其特殊形式);
  • 包含:
    • :通常用 V (Vertex) 表示頂點集合;
    • :通常用 E (Edge) 表示邊的集合;
      — 邊是頂點對:(v,w)E,其中 v,wV ;
      — 又向邊 <v,w> <script type="math/tex" id="MathJax-Element-7"> </script>表示從 v 指向w的邊(單行線);
      — 不考慮重邊與回路。
  • 6.1.2 抽象數據類型


    6.1.3 常見術語


  • :無向圖中頂點之間的邊無方向性,邊 (w,v) (v,w) ;

  • :有向圖中頂點之間的邊有方向性,邊 <w,v> <script type="math/tex" id="MathJax-Element-14"> </script>不同 <v,w> <script type="math/tex" id="MathJax-Element-15"> </script>;

  • :圖中出現重邊,則稱之為非簡單圖;

  • :如果 (v,w) 是無向圖中任意一條邊,那么稱 v w互為“鄰接點”;如果 <v,w> <script type="math/tex" id="MathJax-Element-21"> </script>是有向圖中任意一條邊,那么稱 v 鄰接到終點w,也稱 w 鄰接自終點v。

  • :一個有向圖中,如果任意兩頂點之間都有方向互為相反的兩條弧相連接,則稱“有向完全圖”;一個含有 n 個頂點的有向完全圖中,共有n(n?1)/2條邊。

  • :一個圖的”稠密度“定義為平均頂點度 2|E|/|V| 稠密圖可定量地定義為 |V| 。

  • :邊上附加一個數值信息我們稱之為;邊上帶權的圖稱為網圖或“網絡”。

  • 、、 :頂點 v 是指依附于該頂點的邊數。在有向圖中,頂點的度分為出度入度。
  • 6.1.4 怎么在程序中表示一個圖


    1.
    優勢

    • 直觀、簡單、好理解;
    • 方便檢查任意一對頂點間是否存在邊;
    • 方便找任一頂點的所有“鄰接點”(有邊直接相連的頂點);
    • 方便計算任一頂點的“ ”(從該點發出的邊數為“出度”,指向該點的邊數為“入度”);
      無向圖:對應行(或列)非0元素的個數;
      有向圖:對應非0 元素的個數是“出度”;對應非0元素的個數是“入度”。

    劣勢

    • 浪費空間(特別是稀疏圖);
    • 浪費時間 (例如:統計稀疏圖中一共有多少條邊)。

    2.
    用一個長度為N(N+1)/2 的1 維數組A存儲; {G00,G10,G11,,G(n?1)0,,G(n?1)(n?1)} ,則 Gij A 中對應的下標是:
    i?(i+1)/2+j
    對于 ,只要把 G[i][j] 的值定義為邊 <vi,vj> <script type="math/tex" id="MathJax-Element-43"> </script>的權重即可。


    3.

    • 方便找任一頂點的所有“鄰接點”;
    • 節約 的空間;
      – 需要 N 頭指針 + 2E結點(每個結點至少 2 )。
    • 方便計算任一頂點的“”?
      – 對無向圖:是的;
      – 對有向圖:只能計算“出度”;需要構造“逆鄰接表”(存指向自己的邊)來方便計算“入度”。
    • 方便檢查任意一對頂點間是否存在邊?( No
  • 用一維數組G[ ]存儲有4個頂點的無向圖如下:
    G[]=0,1,0,1,1,0,0,0,1,0 則頂點2和頂點0之間是有邊的。(對或錯?)
    :對,記得從0開始計數,運用數組的公式 i?(i+1)/2+j 。

  • 用鄰接表表示有 N 個頂點、E條邊的圖,則遍歷圖中所有邊的時間復雜度為: O(N+E) 。

  • 6.2 圖的遍歷

    6.2.1 深度優先搜索(Depth First Search,DFS)



    若有 N 個頂點、E條邊, 是:
    - 用鄰接表存儲圖,有 O(N+E) ;
    - 用鄰接矩陣存儲圖,有 O(N2) ;

    6.2.2 廣度優先搜索 (Breadth First Search, BFS)



    若有 N 個頂點、E條邊, 是:
    - 用鄰接表存儲圖,有 O(N+E) ;
    - 用鄰接矩陣存儲圖,有 O(N2)

    6.2.3 DFS和BFS的優點和缺點


    BFS :一種基于隊列這種數據結構的搜索方式,它的特點是由每一個狀態可以擴展出許多狀態,然后再以此擴展,直到找到目標狀態或者隊列中頭尾指針相遇,即隊列中所有狀態都已處遍歷完畢。
    - 優點:對于解決最短或最少問題特別有效,而且尋找深度小;
    - 缺點:內存耗費量大,需要開辟大量的數組單元用來存儲狀態。

    DFS :基于遞歸的搜索方式,它的特點是由一個狀態擴展到另外一個狀態,然后不停地擴展,直到找到目標或者無法繼續到另一個狀態。
    - 優點:占內存少,對于解決連通性性問題比較有效,能找到最優解(一定條件下),但能很快找到接近解;
    - 缺點:可能不必遍歷所有分枝(也就是速度快),在深度很大的情況下效率不高。

    6.2.4 圖不連通怎么辦?

  • :如果從 V W存在一條(無向)路徑 ,則稱V 和W 是連通的。
  • V W的路徑是一系列頂點 {V,v1,v2,,vn,W} 的集合,其中任一對相鄰的頂點間都有圖中的邊。 是路徑中的邊數(如果帶權,則是所有邊的權重和)。如果 V W之間的所有頂點都不同,則稱之間的所有頂點都不同,則稱
  • :起點等于終點的路徑。
  • :圖中任意兩頂點均連通。
  • 無向圖極大 連通子圖
    • 極大頂點數:再加1個頂點就不連通了;
    • 極大邊數:包含子圖中所有頂點相連的所有邊。
  • 有向圖中頂點 V W之間存在雙向路徑,則稱 V W是強連通的。
  • 有向圖任意兩頂點均強連通。
  • 有向圖極大強連通子圖。
  • 打印每個連通圖:

    6.3


    /* queue 模板類的定義在<queue>頭文件中。 與stack 模板類很相似,queue 模板類也需要兩個模板參數,一個是元素類型,一個容器類 型,元素類型是必要的,容器類型是可選的,默認為deque 類型。 定義queue 對象的示例代碼如下: queue<int> q1; queue<double> q2;queue 的基本操作有: 入隊,如例:q.push(x); 將x 接到隊列的末端。 出隊,如例:q.pop(); 彈出隊列的第一個元素,注意,并不會返回被彈出元素的值。 訪問隊首元素,如例:q.front(),即最早被壓入隊列的元素。 訪問隊尾元素,如例:q.back(),即最后被壓入隊列的元素。 判斷隊列空,如例:q.empty(),當隊列空時,返回true。 */ #include<iostream> #include<string.h> #include "queue" using namespace std; int M[10][10]; //存儲圖的矩陣; bool visited[10]; //看圖中的每個節點是否訪問過; int result[10]; //存放結果的矩陣; int vertex,ridge; //頂點和邊 int k; //計每一個鄰接表存儲的結果 void DFS(int x) { /*深度搜索*/int i;result[k++] = x;visited[x] = true;for(i = 0;i < vertex; i++){if(M[x][i] == 1 && !visited[i])/*是否有邊;是否訪問過*/DFS(i);} }void BFS(int x) {int i;queue<int> q;q.push(x);visited[x] = 1;result[k++] = x;while (!q.empty()) {int l = q.front();q.pop(); for ( i = 0; i < vertex; i++) {if (M[l][i] == 1 && !visited[i]) {/*是否有邊;是否訪問過*/visited[i] = 1;result[k++] = i;q.push(i);}}} }int main() {int i,j,m,n;cin>>vertex>>ridge;/*初始化*/memset(visited,0, sizeof(visited)); //visited數列全部為0for(i = 0;i < vertex;i++){for(j = 0; j < ridge; j++){M[i][j] = 0;}}while(ridge--){cin>>m>>n;M[m][n] = 1;M[n][m] = 1;}/*開始進行深度搜索*/for(i = 0;i < vertex;i++ ){k = 0;if(!visited[i]){DFS(i);cout<<"{ ";for(j = 0;j < k;j++)cout<<result[j]<<" ";cout<<"}"<<endl;}}/*開始進行廣度搜索*/memset(visited, 0, sizeof(visited));for ( i = 0; i < vertex; i++){k = 0;if (!visited[i]) {BFS(i);cout << "{ ";for ( j = 0; j < k; j++)cout << result[j] << " ";cout << "}" << endl;}}//system("pause");return 0; }

    6.4


    #include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> #include <vector> #include <queue> #include <set> #include <map> #include <string> #include <math.h> #include <stdlib.h> #include <time.h> /*邦德*/ using namespace std; const int inf=1<<30; struct node {double x,y; } a[100+5]; int n,vis[100+5],b[100+5],ans[100+5],cnt; double d,ansfirst,nowfirst; int dis(node d1,node d2) {if(d*d<(d1.x-d2.x)*(d1.x-d2.x)+(d1.y-d2.y)*(d1.y-d2.y)) return 0;return 1; } int first(int d1) {if(sqrt(a[d1].x*a[d1].x+a[d1].y*a[d1].y)>d+7.5) return 0;else return 1; }double first1(int d1) {return sqrt(a[d1].x*a[d1].x+a[d1].y*a[d1].y)-7.5; } int safe(node d1) {if(d1.x>=50-d) return 1;if(d1.y>=50-d) return 1;if(d1.x<=-50+d) return 1;if(d1.y<=-50+d) return 1;return 0; } void dfs(int d1,int now) {int i;if(safe(a[d1])){//printf("%d %.2f\n",now,nowfirst);if(now<cnt){for(i=0; i<now; i++)ans[i]=b[i];cnt=now;ansfirst=nowfirst;}else if(now==cnt&&ansfirst>nowfirst){for(i=0; i<now; i++)ans[i]=b[i];cnt=now;ansfirst=nowfirst;}return ;}else{for(i=1; i<=n; i++){if(!vis[i]&&dis(a[d1],a[i])){vis[i]=1;b[now]=i;dfs(i,now+1);vis[i]=0;}}}return; } int main() {int i;while(~scanf("%d%lf",&n,&d)){a[0].x=a[0].y=0;for(i=1; i<=n; i++){scanf("%lf%lf",&a[i].x,&a[i].y);}if(d+7.5>=50){printf("1\n");return 0;}ansfirst=(double)inf;cnt=inf;memset(ans,0,sizeof(ans));for(i=1; i<=n; i++){memset(vis,0,sizeof(vis));if(!vis[i]&&first(i)){nowfirst=first1(i);if(safe(a[i])){if(ansfirst>nowfirst){ans[0]=i;cnt=1;ansfirst=nowfirst;}}vis[i]=1;memset(b,0,sizeof(b));b[0]=i;dfs(i,1);}}if(cnt==inf) printf("0\n");else{printf("%d\n",cnt+1);for(i=0; i<cnt; i++){printf("%.0f %.0f\n",a[ans[i]].x,a[ans[i]].y);}}}return 0; }

    6.5


    /* 題意: 找到一個圖中每個節點通過最多5條邊 能找到的所有節點 然后輸出百分比思路:廣搜 記錄層數為6以內的所有節點本題的關鍵在于 如何記錄節點當前的層數 1. 引入2個變量 last tail 分別指向 當前層數的最后一個元素 和 下一層的最后一個元素 2. 若當前出隊的元素與last相等 則說明即將進入下一層 將last更新為tail 更新tail 重復~~知道level = 6 或者隊列空 */ /*6度空間*/ #include "iostream" #include "stdio.h" #include "queue" using namespace std; bool map[10001][10001] = {false}; int n, m; int Count; void bfs(int x) {bool visited[10001] = { false };queue<int>q;q.push(x);visited[x] = true;int level = 0; /* 記錄層數 */int last = x; /* 記錄當前層數的最后一個元素 */int tail; /* 指向下一層最后一個元素 */while (!q.empty()) {x = q.front();q.pop();for (int i = 1; i <= n; i++) {if (!visited[i] && map[x][i] == 1) {q.push(i); /* 進隊 */Count++;visited[i] = true;tail = i;}}if (last == x) {level++;last = tail;}if (level == 6)break;} } int main() {cin >> n >> m;for (int i = 0; i < m; i++) { int k, l;cin >> k >> l;map[k][l] = 1;map[l][k] = 1;}for (int i = 1; i <=n; i++) { /* 對于所有節點 做bfs() */Count = 1;bfs(i);cout << i << ": ";float answer = (float)Count / n * 100;printf("%.2f%%\n", answer);}return 0; }

    總結

    以上是生活随笔為你收集整理的陈越《数据结构》第六讲 图(上)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。