【數據結構_浙江大學MOOC】第六七八講 圖

列出連通集

題目

給定一個有N個頂點和E條邊的無向圖,請用DFS和BFS分別列出其全部的連通集。假設頂點從0到N−1編號。進行搜索時,假設咱們老是從編號最小的頂點出發,按編號遞增的順序訪問鄰接點。ios

輸入格式:
輸入第1行給出2個整數N(0<N≤10)和E,分別是圖的頂點數和邊數。隨後E行,每行給出一條邊的兩個端點。每行中的數字之間用1空格分隔。算法

輸出格式:
按照 ${v_1, v_2, ···, v_k}$ 的格式,每行輸出一個連通集。先輸出DFS的結果,再輸出BFS的結果。編程

輸入樣例:數組

8 6
0 7
0 1
2 0
4 1
2 4
3 5

輸出樣例:數據結構

{ 0 1 4 2 7 }
{ 3 5 }
{ 6 }
{ 0 1 2 7 4 }
{ 3 5 }
{ 6 }

實現代碼

#include <cstdio>
#include <queue>
#include <iostream>
using namespace std;
#define MAX 10
int a[MAX][MAX], dfs_visited[MAX], bfs_visited[MAX], N, E;  //dfs_visited數組表示dfs
queue<int> q;
void dfs(int c){
    dfs_visited[c] = 1;         //1表示訪問過了
    printf(" %d", c);
    for(int i = 0; i < N; i++)
        if(a[c][i] && !dfs_visited[i])  //利用二維數組的一行就是該節點的鄰接點,若是那個鄰接點還沒沒訪問過則遞歸訪問
            dfs(i);
}
void bfs(int c){
    bfs_visited[c] = 1;         //1表示訪問過了
    q.push(c);
    printf(" %d", c);
    while(!q.empty()){  //若是隊列不空則每次從隊列中取出一個節點找出該節點的第一層bfs節點,並加入隊列中
        int temp = q.front();
        q.pop();
        for(int i = 0; i < N; i++){     //找出第一層bfs的節點,依次輸出並加入隊列,跟樹的層次遍歷很像
            if(a[temp][i] && !bfs_visited[i]){
                printf(" %d", i);       
                bfs_visited[i] = 1;
                q.push(i);
            }       
        }
    }
}
int main(){
    int temp1, temp2;
    scanf("%d%d", &N, &E);
    for(int i = 0; i < E; i++){
        scanf("%d%d", &temp1, &temp2);
        a[temp1][temp2] = 1;        //由於是無向圖全部鄰接矩陣是關於主對角線對稱的
        a[temp2][temp1] = 1;
    }
    for(int i = 0; i < N; i++){
        if(!dfs_visited[i]){
            putchar('{');
            dfs(i);
            printf(" }\n");
        }
    }

    for(int i = 0; i < N; i++){
        if(!bfs_visited[i]){
            putchar('{');
            bfs(i);
            printf(" }\n");
        }
    }
    return 0;
}

提交結果

clipboard.png

哈利·波特的考試

題目

哈利·波特要考試了,他須要你的幫助。這門課學的是用魔咒將一種動物變成另外一種動物的本事。例如將貓變成老鼠的魔咒是haha,將老鼠變成魚的魔咒是hehe等等。反方向變化的魔咒就是簡單地將原來的魔咒倒過來念,例如ahah能夠將老鼠變成貓。另外,若是想把貓變成魚,能夠經過念一個直接魔咒lalala,也能夠將貓變老鼠、老鼠變魚的魔咒連起來念:hahahehe。框架

如今哈利·波特的手裏有一本教材,裏面列出了全部的變形魔咒和能變的動物。老師容許他本身帶一隻動物去考場,要考察他把這隻動物變成任意一隻指定動物的本事。因而他來問你:帶什麼動物去可讓最難變的那種動物(即該動物變爲哈利·波特本身帶去的動物所須要的魔咒最長)須要的魔咒最短?例如:若是隻有貓、鼠、魚,則顯然哈利·波特應該帶鼠去,由於鼠變成另外兩種動物都只須要念4個字符;而若是帶貓去,則至少須要念6個字符才能把貓變成魚;同理,帶魚去也不是最好的選擇。數據結構和算法

輸入格式:
輸入說明:輸入第1行給出兩個正整數N (≤100)和M,其中N是考試涉及的動物總數,M是用於直接變形的魔咒條數。爲簡單起見,咱們將動物按1~N編號。隨後M行,每行給出了3個正整數,分別是兩種動物的編號、以及它們之間變形須要的魔咒的長度(≤100),數字之間用空格分隔。函數

輸出格式:
輸出哈利·波特應該帶去考場的動物的編號、以及最長的變形魔咒的長度,中間以空格分隔。若是隻帶1只動物是不可能完成全部變形要求的,則輸出0。若是有若干只動物均可以備選,則輸出編號最小的那隻。性能

輸入樣例:學習

6 11
3 4 70
1 2 1
5 4 50
2 6 50
5 6 60
1 3 70
4 6 60
3 6 80
5 1 100
2 4 60
5 2 80

輸出樣例:

4 70

解讀題目

本題能夠視爲一個無向帶權圖,題目裏以字符長度來衡量難度,所以帶鼠去,不管是變貓仍是變魚,都只須要4個字符。在輸入樣例中,第一行的6表明動物個數,即圖裏面頂點的個數,11表示邊的個數,接下來的每一行給出兩個頂點和它們之間的權重,這些數據對應一張無向的網圖。

本題的目的在於找出任意兩個頂點之間的最短路徑,用 FLoyd 算法。將圖用鄰接矩陣表示後,對每個頂點掃描它到其它頂點的最大值, 記錄下來,再在這些最大值裏找一個最小值,即咱們想要獲得的那個頂點。在本題中,也就是哈利應該帶該點所對應的動物去。這樣,咱們就成功的幫哈利完成了考試該帶什麼去的難題!

clipboard.png

程序框架以下:

int main()
{
    Graph G = BuildGraph();    //讀入圖
    FindAnimal(G);    //分析圖
    return 0;
}

實現代碼

#include<iostream>
#include<fstream>
using namespace std;
//ifstream InFile("C:\\Users\\DELL\\Desktop\\in.txt",ios::in);
 
#define MaxVertexNum 200    //最大頂點數設爲100
#define INFINITY1 65535      //∞設爲雙字節無符號整數的最大值65535
typedef int Vertex;         //用頂點下標表示頂點,爲整形
typedef int WeightType;    //邊的權值設爲整形
typedef char DataType;     //頂點儲存的數據類型設爲字符型
 
 
//圖結點的定義
typedef struct GNode* PtrToGNode;
struct GNode{
    int Nv;                //頂點數
    int Ne;                //邊數
    WeightType G[MaxVertexNum][MaxVertexNum];   //鄰接矩陣
    DataType Data[MaxVertexNum];                //存頂點的數據
    //注意:若頂點無數據,此時Data[]能夠不出現
};
typedef PtrToGNode MGraph;
 
 
 
 
//邊的定義
typedef struct ENode* PtrToENode;
struct ENode{
    Vertex V1,V2;                      //無向邊(v1,v2)
    WeightType Weight;                 //權重
};
typedef PtrToENode Edge;
 
 
 
 
MGraph CreateGraph(int VertexNum)
{
    MGraph Graph = new GNode;
    Graph->Nv = VertexNum;
    Graph->Ne = 0;
    for(int i=0;i<Graph->Nv+2 ;++i){
        for(int j=0;j<Graph->Nv+2 ;++j){
            Graph->G[i][j] = INFINITY1;
        }
    }
    return Graph;
}
 
 
 
 
void InsertEdge(MGraph Graph,Edge E)
{
    Graph->G[E->V1][E->V2] = E->Weight;
    Graph->G[E->V2][E->V1] = E->Weight;
}
 
 
MGraph BulidGraph()
{
    Vertex N,M;
    cin >> N>>M;
    Edge E=new ENode;
    MGraph Graph = CreateGraph(N);
    if(Graph->Nv >0){
        for(int i=0;i<M;++i){
            cin >> E->V1 >> E->V2 >> E->Weight;
            InsertEdge(Graph, E);
        }
    }
 
    return Graph;
 
}
 
 
 
//Floyd
bool Floyd(MGraph Graph,WeightType D[][MaxVertexNum])
{
    for(int i=0;i<Graph->Nv +2;++i){
        for(int j=0;j<Graph->Nv +2;++j){
            D[i][j] = Graph->G[i][j];
        }
    }
 
    for(int k=1;k<=Graph->Nv ;++k){
        for(int i=0;i<=Graph->Nv ;++i){
            for(int j=0;j<=Graph->Nv ;++j){
                if(i!=j&&D[i][k]+D[k][j]<D[i][j]){
                    D[i][j] = D[i][k] + D[k][j];
                    if (i == j&&D[i][j]<0) {
                        return false;
                    }
 
                }
            }
        }
    }
 
    return true;
}
 
void FindAnimal(MGraph Graph)
{
    WeightType D[MaxVertexNum][MaxVertexNum];
    WeightType Max[MaxVertexNum];
    Floyd(Graph, D);
    
    
    for(int i=1;i<=Graph->Nv ;++i){
        int m = -1;
        for(int j=1;j<=Graph->Nv ;++j){
            if(i!=j&&m<D[i][j]){
                m = D[i][j];
            }
            if(i!=j&&D[i][j]==INFINITY1){
                cout << 0 << endl;
                return;
            }
        }
        Max[i] = m;
    }
    int ret = 1;
    for(int i = 2; i <= Graph->Nv; ++i){
        //cout << Max[i] << endl;
        if(Max[ret]>Max[i]){
            ret = i;
        }
    }
    cout << ret << " " << Max[ret] << endl;
}
 
int main()
{
    MGraph Graph = BulidGraph();
    FindAnimal(Graph);
    delete Graph;
    //InFile.close();
    system("pause");
    return 0;
}

提交結果

clipboard.png

旅遊規劃

題目

有了一張自駕旅遊路線圖,你會知道城市間的高速公路長度、以及該公路要收取的過路費。如今須要你寫一個程序,幫助前來諮詢的遊客找一條出發地和目的地之間的最短路徑。若是有若干條路徑都是最短的,那麼須要輸出最便宜的一條路徑。

輸入格式:
輸入說明:輸入數據的第1行給出4個正整數N、M、S、D,其中N(2≤N≤500)是城市的個數,順便假設城市的編號爲0~(N−1);M是高速公路的條數;S是出發地的城市編號;D是目的地的城市編號。隨後的M行中,每行給出一條高速公路的信息,分別是:城市一、城市二、高速公路長度、收費額,中間用空格分開,數字均爲整數且不超過500。輸入保證解的存在。

輸出格式:
在一行裏輸出路徑的長度和收費總額,數字間以空格分隔,輸出結尾不能有多餘空格。

輸入樣例:

4 5 0 3
0 1 1 20
1 3 2 30
0 3 4 10
0 2 2 20
2 3 1 20

輸出樣例:

3 40

題目解讀

這是一個圖論裏單源最短路徑問題,咱們用 Dijkstra 算法解決。這道題裏面城市爲結點,公路爲邊。一個複雜的問題是每一條邊的權重,在這道題裏有距離收費兩種權重,首先要找距離意義上最短路徑,當最短路不止一條的時候,就須要找收費最短的路。

根據輸入樣例,有下面的圖:

clipboard.png

綠色表示權重距離,紫色表示權重收費。咱們用基於 Dijkstra 算法的方法來解決,首先以距離爲權重應用 Dijkstra 算法,咱們知道到每收錄一個結點的時候要判斷其它結點有沒有被影響,會不會獲得一個更短的距離,若是更短的話咱們要更新這個距離,若是是等長的話,在本來的 Dijkstra 算法中就什麼都不作了,但在本題中,當距離相等的時候,咱們還須要按照收費來作一個更新。

實現代碼

#include<iostream>
using namespace std;
 
#define MaxNum 10000
 
typedef int ElemType;
 
int main()
{
    int N,M;
    ElemType S,D;
    cin>>N>>M>>S>>D;
    //用鄰接矩陣存儲圖 
    int **len = new int*[N];    //儲存公路長度
    int **cost = new int*[N];    //儲存費用
        for(int i=0; i<N; i++)
    {
            len[i] = new int[N];
            cost[i] = new int[N];
        }              
    //初始化
    for(int i=0;i<N;i++)
    {
        for(int j=0;j<N;j++)
        {
            len[i][j] = MaxNum;
            cost[i][j] = MaxNum;
        }
    } 
    //構建鄰接矩陣,處理輸入數據
    for(int i=0;i<M;i++)
    {
        ElemType c1,c2;
         int l,c;
         cin>>c1>>c2>>l>>c;
         len[c1][c2] = l;
         len[c2][c1] = l;
         cost[c1][c2] = c;
         cost[c2][c1] = c;
    } 
      
    //Dijastra算法開始
    int *dist = new int[N];    //記錄當前路徑長度
    int *acost = new int[N];    //記錄當前花費
    //初始化
    for(int i=0;i<N;i++)
    {
        dist[i] = MaxNum;
          acost[i] = MaxNum;
    } 
    dist[S] = 0;
    acost[S] = 0;
       
    //進行算法
     for(int k=0;k<2;k++)
    {
           for(int v=0;v<N;v++)
        {
            for(int w=0;w<N;w++)
            {
                   if(dist[v] != MaxNum)
                {
                       if(dist[v]+len[v][w] < dist[w])
                           dist[w] = dist[v] + len[v][w];                        
                    else if(dist[v] + len[v][w] == dist[w] && acost[v] != MaxNum && acost[v]+cost[v][w] <acost[w])
                        acost[w] = acost[v] + cost[v][w];                            
                }
            }                                        
        }                                               
    }         
    cout<<dist[D] << " " <<acost[D] <<endl;
    return 0;
}

提交結果

clipboard.png


關於浙江大學MOOC數據結構課程的習題記錄就到這裏了,主要記錄了線性表的必作編程題內容,附上課程大綱:

第一講 基本概念(1:15:26)[陳越]

1.1 什麼是數據結構(4節共32:43)

1.2 什麼是算法(3節共22:41)

1.3 應用實例:最大子列和問題(3節共20:02)

第二講 線性結構(2:19:00)[何欽銘]

2.1 線性表及其實現(6小節共45:04)

2.2 堆棧(4小節共39:51)

2.3 隊列(2小節共15:45)

2.4 應用實例:多項式加法運算(1小節10:37)

小白專場:多項式乘法與加法運算- C實現(3小節共27:43)

第三講 樹(上) (1:50:08)[何欽銘]

3.1 樹與樹的表示(5小節共38:54)

3.2 二叉樹及存儲結構(2小節共16:43)

3.3 二叉樹的遍歷(4小節共37:02)

小白專場:樹的同構 - C語言實現(2小節共17:29)

第四講 樹(中)(1:06:31)[何欽銘]

4.1 二叉搜索樹(3小節共20:57)

4.2 平衡二叉樹(2小節共22:53)

小白專場:是否同一棵二叉搜索樹- C實現(3小節共22:41)

線性結構之習題選講[陳越]:Reversing Linked List(3小節共13:08)

第五講 樹(下)(1:53:28)[何欽銘]

5.1 堆(4小節共30:05)

5.2 哈夫曼樹與哈夫曼編碼(3小節共19:52)

5.3 集合及運算(2小節共12:57)

小白專場:堆中的路徑 - C語言實現(1小節共7:51)

小白專場[陳越]:File Transfer - C語言實現(4小節共42:43)

第六講 圖(上)(1:29:32)[陳越]

6.1 什麼是圖(3小節共24:02)

6.2 圖的遍歷(4小節共22:22)

6.3 應用實例:拯救007(1小節共14:40)

6.4 應用實例:六度空間(1小節共8:06)

小白專場:如何創建圖- C語言實現(6小節共20:22)

第七講 圖(中)(2:11:35)[陳越]

樹之習題選講-Tree Traversals Again(2小節共12:16)

樹之習題選講-Complete Binary Search Tree(3小節共25:47)

樹之習題選講- Huffman Codes(3小節共18:11)

7.1 最短路徑問題(6小節共56:38)

小白專場:哈利•波特的考試- C語言實現(4小節共18:43)

第八講 圖(下)(57:02)[陳越]

8.1 最小生成樹問題(2小節共20:16)

8.2 拓撲排序(2小節共27:57)

圖之習題選講-旅遊規劃(2小節共8:49)

第九講 排序(上)(1:11:44)[陳越]

9.1 簡單排序(冒泡、插入)(4小節共23:26)

9.2 希爾排序(1小節共9:29)

9.3 堆排序(2小節共10:27)

9.4 歸併排序(3小節共28:22)

第十講 排序(下)(54:20)[陳越]

10.1 快速排序(4小節共25:25)

10.2 表排序(2小節共12:41)

10.3 基數排序(3小節共12:13)

10.4 排序算法的比較(1小節共4:01)

第十一講 散列查找(1:43:39)[何欽銘]

11.1 散列表(2小節共13:43)

11.2 散列函數的構造方法(2小節共13:05)

11.3 衝突處理方法(6小節共36:26)

11.4 散列表的性能分析(1小節10:26)

11.5 應用實例:詞頻統計(1小節6:01)

小白專場[陳越]:電話聊天狂人- C語言實現(4小節共23:58)

第十二講 綜合習題選講(30:12) [陳越]

習題選講-Insert or Merge(2小節共11:51)

習題選講-Sort with Swap(0,*)(2小節共11:06)

習題選講-Hashing - Hard Version(1小節共7:15)


最後給出一張數據結構和算法的思惟導圖:

clipboard.png

剩下的內容將在以後的算法學習中進行。


參考連接:
06-圖1 列出連通集 (25分)
07-圖4 哈利·波特的考試(25 分)
旅遊規劃

$$$$不足之處,歡迎指正。

相關文章
相關標籤/搜索