在前幾節說過了樹結構,從這一節開始,開始進入圖。node
圖是由若干給定的頂點及鏈接兩頂點的邊所構成的圖形,這種圖形一般用來描述某些事物之間的某種特定關係。 頂點用於表明事物,鏈接兩頂點的邊則用於表示兩個事物間具備這種關係。數組
有1~N個節點,很天然的想到,咱們能夠構建一個二維數組G[N-1][N-1],令G[i][j]=1或0,不爲零時表示第i個節點有指向第j個節點的路路徑。在一個無向圖中,必有G[i][j] = G[j][i],由於它是對稱的。對於無向圖爲了節省空間咱們能夠只開一個三角形的二維數組,只保留下三角。
對於帶權路徑圖,只需將G[i][j]設置爲權值。微信
優勢:網絡
缺點:數據結構
代碼實現:app
#include <cstdio> #include <stdlib.h> #include <string.h> #define WeightType int #define MAXSIZE 100 #define DataType int #define Vertex int using namespace std; //Use the adjacency matrix to represent the graph typedef struct GNode* Graph; struct GNode { int Nvertex; int Nedge; WeightType graph[MAXSIZE][MAXSIZE]; DataType Data[MAXSIZE]; }; typedef struct ENode* Edge; struct ENode { Vertex begin; Vertex end; WeightType weight; }; //build edge Edge BuildEdge(Vertex begin, Vertex end, WeightType weight) { Edge e = (Edge)malloc(sizeof(struct ENode)); e->begin = begin; e->end = end; e->weight = weight; return e; } //creat empty graph Graph CreateGraph(int VertexNum) { Graph G = (Graph)malloc(sizeof(struct GNode)); G->Nvertex = VertexNum; G->Nedge = 0; for (int i = 0; i < G->Nvertex; i++) { for (int j = 0; j < G->Nvertex; j++) { G->graph[i][j] = 0; } } return G; } //insert edge void InsertEdge(Graph G, Edge e) { G->graph[e->begin][e->end] = e->weight; //If it is an undirected graph, you need to add the following G->graph[e->end][e->begin] = e->weight; G->Nedge++; } //build graph Graph BuildGraph() { int Nvertex, Nedge; scanf_s("%d %d", &Nvertex, &Nedge); Graph G = CreateGraph(Nvertex); for (int i = 0; i < Nedge; i++) { Vertex begin, end; WeightType weight; scanf_s("%d %d %d", &begin, &end, &weight); InsertEdge(G, BuildEdge(begin, end, weight)); } return G; } int main() { Graph G = BuildGraph(); for (int i = 1; i <= G->Nvertex; i++) { for (int j = 1; j <= G->Nvertex; j++) { if (G->graph[i][j] != 0) { printf("%d->%d\n", i, j); } } } return 0; }
有1~N個節點,咱們構建一個一維指針數組G[N],G[i]做爲第i個節點的頭節點,將全部與其相鄰的節點,串成一條鏈表。
優勢:ide
缺點:工具
代碼實現:ui
#include <cstdio> #include <stdlib.h> #include <string.h> #define WeightType int #define MAXSIZE 100 #define DataType int #define Vertex int using namespace std; //Use the adjacency List to represent the graph typedef struct AdjVNode* PtrToAdjVNode; struct AdjVNode { Vertex Adjv; WeightType Wight; PtrToAdjVNode Next; }; typedef struct VNode AdjList[MAXSIZE]; struct VNode { PtrToAdjVNode first; DataType Data; }; typedef struct GNode* Graph; struct GNode { int Nvertex; int Nedge; AdjList graph; }; typedef struct ENode* Edge; struct ENode { Vertex begin; Vertex end; WeightType weight; }; //build edge Edge BuildEdge(Vertex begin, Vertex end, WeightType weight) { Edge e = (Edge)malloc(sizeof(struct ENode)); e->begin = begin; e->end = end; e->weight = weight; return e; } //creat empty graph Graph CreateGraph(int VertexNum) { Graph G = (Graph)malloc(sizeof(struct GNode)); G->Nvertex = VertexNum; G->Nedge = 0; for (int i = 0; i <= G->Nvertex; i++) { G->graph[i].first = NULL; } return G; } //insert edge void InsertEdge(Graph G,Edge e) { PtrToAdjVNode newnode = (PtrToAdjVNode)malloc(sizeof(struct AdjVNode)); newnode->Wight = e->weight; newnode->Adjv = e->end; newnode->Next = G->graph[e->begin].first; G->graph[e->begin].first = newnode; //If it is an undirected graph, you need to add the following newnode = (PtrToAdjVNode)malloc(sizeof(struct AdjVNode)); newnode->Wight = e->weight; newnode->Adjv = e->begin; newnode->Next = G->graph[e->end].first; G->graph[e->end].first = newnode; } //build graph Graph BuildGraph() { int Nvertex, Nedge; scanf_s("%d %d", &Nvertex, &Nedge); Graph G = CreateGraph(Nvertex); for (int i = 0; i < Nedge; i++) { Vertex begin, end; WeightType weight; scanf_s("%d %d %d",&begin,&end,&weight); InsertEdge(G, BuildEdge(begin, end, weight)); } return G; } int main() { Graph G = BuildGraph(); for (int i = 1; i <= G->Nvertex; i++) { PtrToAdjVNode temp = G->graph[i].first; while (temp) { printf("%d->%d\n", i, temp->Adjv); temp = temp->Next; } } return 0; }
以前在說樹這種數據結構的時候,有說到過中序,先序,後序遍歷,還有層序遍歷,前三種被叫作深度優先遍歷,層序遍歷是廣度優先遍歷spa
與數的程序遍歷類似,對數的程序遍歷是一層一層的入隊又出隊,一樣的從一個節點開始,將全部他指向的節點入隊,出對時又將他們所指向的節點入隊。一樣,與樹的遍歷的不一樣,圖中節點交錯,一個節點不止有惟一一個節點指向他,故咱們用一個bool數組,默認是未訪問過(false),當訪問事後該節點就將其設置爲true。一旦某個節點已經被訪問過咱們將再也不對其入隊。
#define ElementType Vertex typedef struct QNode* Queue; struct QNode { ElementType Data[MAXSIZE]; int front; int rear; }; Queue makeempty() { Queue Q = (Queue)malloc(sizeof(struct QNode)); Q->front = 0; Q->rear = 0; return Q; } void QueueAdd(ElementType value, Queue ptrq) { if ((ptrq->rear + 1) % MAXSIZE == ptrq->front) { printf("The quque has been full."); return; } ptrq->rear = (++ptrq->rear) % MAXSIZE; ptrq->Data[ptrq->rear] = value; } ElementType QueueDelete(Queue ptrq) { if (ptrq->front == ptrq->rear) { printf("The queue has been empty."); return -1; } ptrq->front = (++ptrq->front) % MAXSIZE; return ptrq->Data[ptrq->front]; } bool isEmpty(Queue Q) { if (Q->front == Q->rear) { return true; } else { return false; } } //BFS void BFS(Graph G, Vertex x, bool b[]) { //若是已經訪問過直接退出 if (b[x]) { return; } b[x] = true; Queue Q = makeempty(); QueueAdd(x,Q); while (!isEmpty(Q)) { Vertex v = QueueDelete(Q); printf("%d\n", v); for (int i = 0; i < G->Nvertex; i++) { if (G->graph[v][i] != 0 && b[i] != true) { b[i] = true; QueueAdd(i, Q); } } } }
顧名思義,就是優先了往深了走,直到不能走了回退,看是否有其餘的路可走,能夠用一個遞歸的形式去描繪,與樹的遍歷的不一樣,圖中節點交錯,一個節點不止有惟一一個節點指向他,故咱們用一個bool數組,默認是未訪問過(false),當訪問事後該節點就將其設置爲true。
void DFS(Graph G,Vertex x,bool b[]) { //若是已經訪問過直接退出 if (b[x]) { return; } printf("%d\n", x); b[x] = true; for (int i = 0; i < G->Nvertex; i++) { if (G->graph[x][i] != 0 && b[i] != true) { DFS(G, i, b); } } }
給定一個有N個頂點和E條邊的無向圖,請用DFS和BFS分別列出其全部的連通集。假設頂點從0到N−1編號。進行搜索時,假設咱們老是從編號最小的頂點出發,按編號遞增的順序訪問鄰接點。
輸入格式:
輸入第1行給出2個整數N(0<N≤10)和E,分別是圖的頂點數和邊數。隨後E行,每行給出一條邊的兩個端點。每行中的數字之間用1空格分隔。
輸出格式:
按照"{ v1,v2....vk}"的格式,每行輸出一個連通集。先輸出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 }
題解:
直接對全部節點DFS和BFS輸出全部與其相連的點。(固然訪問過的點就不輸出了 )。
#include <cstdio> #include <stdlib.h> #include <string.h> #include<stdbool.h> #define WeightType int #define MAXSIZE 1000 #define DataType int #define Vertex int #define ElementType Vertex using namespace std; int size; typedef struct QNode* Queue; struct QNode { ElementType Data[MAXSIZE]; int front; int rear; }; //Use the adjacency matrix to represent the graph typedef struct GNode* Graph; struct GNode { int Nvertex; int Nedge; WeightType graph[MAXSIZE][MAXSIZE]; DataType Data[MAXSIZE]; }; typedef struct ENode* Edge; struct ENode { Vertex begin; Vertex end; WeightType weight; }; //build edge Edge BuildEdge(Vertex begin, Vertex end, WeightType weight) { Edge e = (Edge)malloc(sizeof(struct ENode)); e->begin = begin; e->end = end; e->weight = weight; return e; } //creat empty graph Graph CreateGraph(int VertexNum) { Graph G = (Graph)malloc(sizeof(struct GNode)); G->Nvertex = VertexNum; G->Nedge = 0; for (int i = 0; i < G->Nvertex; i++) { for (int j = 0; j < G->Nvertex; j++) { G->graph[i][j] = 0; } } return G; } //insert edge void InsertEdge(Graph G, Edge e) { G->graph[e->begin][e->end] = e->weight; //If it is an undirected graph, you need to add the following G->graph[e->end][e->begin] = e->weight; G->Nedge++; } //build graph Graph BuildGraph() { int Nvertex, Nedge; scanf("%d %d", &Nvertex, &Nedge); size = Nvertex; Graph G = CreateGraph(Nvertex); for (int i = 0; i < Nedge; i++) { Vertex begin, end; WeightType weight; scanf("%d %d", &begin, &end); InsertEdge(G, BuildEdge(begin, end, 1)); } return G; } Queue makeempty() { Queue Q = (Queue)malloc(sizeof(struct QNode)); Q->front = 0; Q->rear = 0; return Q; } void QueueAdd(ElementType value, Queue ptrq) { if ((ptrq->rear + 1) % MAXSIZE == ptrq->front) { printf("The quque has been full."); return; } ptrq->rear = (++ptrq->rear) % MAXSIZE; ptrq->Data[ptrq->rear] = value; } ElementType QueueDelete(Queue ptrq) { if (ptrq->front == ptrq->rear) { printf("The queue has been empty."); return -1; } ptrq->front = (++ptrq->front) % MAXSIZE; return ptrq->Data[ptrq->front]; } bool isEmpty(Queue Q) { if (Q->front == Q->rear) { return true; } else { return false; } } //DFS void DFS(Graph G, Vertex x, bool b[]) { //若是已經訪問過直接退出 if (b[x]) { return; } printf("%d ", x); b[x] = true; for (int i = 0; i < G->Nvertex; i++) { if (G->graph[x][i] != 0 && b[i] != true) { DFS(G, i, b); } } } //BFS void BFS(Graph G, Vertex x, bool b[]) { //若是已經訪問過直接退出 if (b[x]) { return; } b[x] = true; Queue Q = makeempty(); QueueAdd(x, Q); while (!isEmpty(Q)) { Vertex v = QueueDelete(Q); printf("%d ", v); for (int i = 0; i < G->Nvertex; i++) { if (G->graph[v][i] != 0 && b[i] != true) { b[i] = true; QueueAdd(i, Q); } } } } int main() { Graph G = BuildGraph(); bool b[MAXSIZE]; memset(b, false, sizeof(b)); for (int i = 0; i < size; i++) { if (!b[i]) { printf("{ "); DFS(G, i, b); printf("}\n"); } } memset(b, false, sizeof(b)); for (int i = 0; i < size; i++) { if (!b[i]) { printf("{ "); BFS(G, i, b); printf("}\n"); } } return 0; }
This time let us consider the situation in the movie "Live and Let Die" in which James Bond, the world's most famous spy, was captured by a group of drug dealers. He was sent to a small piece of land at the center of a lake filled with crocodiles. There he performed the most daring action to escape -- he jumped onto the head of the nearest crocodile! Before the animal realized what was happening, James jumped again onto the next big head... Finally he reached the bank before the last crocodile could bite him (actually the stunt man was caught by the big mouth and barely escaped with his extra thick boot).
Assume that the lake is a 100 by 100 square one. Assume that the center of the lake is at (0,0) and the northeast corner at (50,50). The central island is a disk centered at (0,0) with the diameter of 15. A number of crocodiles are in the lake at various positions. Given the coordinates of each crocodile and the distance that James could jump, you must tell him whether or not he can escape.
Input Specification:
Each input file contains one test case. Each case starts with a line containing two positive integers N (≤100), the number of crocodiles, and D, the maximum distance that James could jump. Then N lines follow, each containing the (x,y) location of a crocodile. Note that no two crocodiles are staying at the same position.
Output Specification:
For each test case, print in a line "Yes" if James can escape, or "No" if not.
Sample Input 1:
14 20
25 -15
-25 28
8 49
29 15
-35 -2
5 28
27 -29
-8 -28
-20 -35
-25 -20
-13 29
-30 15
-35 40
12 12
Sample Output 1:
Yes
Sample Input 2:
4 13
-12 12
12 12
-12 -12
12 -12
Sample Output 2:
No
題解:
此題無需用圖,只須要將全部位置保存下來便可,作一個DFS尋找是否有出路。首先第1步是從圓點往出跳,給定了圓盤直徑爲15米,由於一個點到圓上的最短距離一定是連着圓心,故在第一跳檢查是否能跳到時跳躍半徑應該爲圓盤半徑加上它的最遠跳躍距離。
每次對節點作DFS,應優先判斷是否能夠直接跳到岸上,由於給定了池塘的邊界,因此咱們只須要用池塘的邊界值(50)減去那個點的對應座標 X軸和Y軸取最小值 (好比(31,-45)這個點,到池塘邊界處最少須要跳min(50-31,50-45)=5)。
代碼:
#include<stdio.h> #include<math.h> #include<algorithm> #include<stdlib.h> #include<stdbool.h> #include<string.h> #define MAXSIZE 101 bool vist[MAXSIZE]; int point[MAXSIZE][2]; int maxjumpdis,N; bool firtJump(int p[]) { if (sqrt(pow(p[0],2) + pow(p[1], 2))<=15+maxjumpdis) { return true; } return false; } bool jump(int p1[],int p2[]) { if (sqrt(pow(p1[0]-p2[0], 2) + pow(p2[1]-p1[1], 2)) <= maxjumpdis) { return true; } return false; } bool isSafe(int p[]) { if (50-abs(p[0])<=maxjumpdis|| 50 - abs(p[1]) <= maxjumpdis) { return true; } return false; } bool DFS(int p[]) { if (isSafe(p)) { return true; } for (int i = 0; i < N; i++) { if (vist[i] != true && jump(point[i],p)) { vist[i] = true; bool safe = DFS(point[i]); if (safe) { return true; } } } return false; } void Save007() { for (int i = 0; i < N; i++) { if (vist[i]!=true&&firtJump(point[i])) { vist[i] = true; bool safe = DFS(point[i]); if (safe) { printf("Yes\n"); return; } } } printf("No\n"); } int main() { memset(vist, false, sizeof(vist)); scanf("%d %d", &N, &maxjumpdis); for (int i = 0; i < N; i++) { scanf("%d %d", &point[i][0], &point[i][1]); } Save007(); return 0; }
「六度空間」理論又稱做「六度分隔(Six Degrees of Separation)」理論。這個理論能夠通俗地闡述爲:「你和任何一個陌生人之間所間隔的人不會超過六個,也就是說,最多經過五我的你就可以認識任何一個陌生人。」
「六度空間」理論雖然獲得普遍的認同,而且正在獲得愈來愈多的應用。可是數十年來,試圖驗證這個理論始終是許多社會學家努力追求的目標。然而因爲歷史的緣由,這樣的研究具備太大的侷限性和困難。隨着當代人的聯絡主要依賴於電話、短信、微信以及因特網上即時通訊等工具,可以體現社交網絡關係的一手數據已經逐漸使得「六度空間」理論的驗證成爲可能。
假如給你一個社交網絡圖,請你對每一個節點計算符合「六度空間」理論的結點佔結點總數的百分比。
輸入格式:
輸入第1行給出兩個正整數,分別表示社交網絡圖的結點數N(1<N≤103 ,表示人數)、邊數M(≤33×N,表示社交關係數)。隨後的M行對應M條邊,每行給出一對正整數,分別是該條邊直接連通的兩個結點的編號(節點從1到N編號)。
輸出格式:
對每一個結點輸出與該結點距離不超過6的結點數佔結點總數的百分比,精確到小數點後2位。每一個結節點輸出一行,格式爲「結點編號:(空格)百分比%」。
輸入樣例:
10 9
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
9 10
輸出樣例:
1: 70.00%
2: 80.00%
3: 90.00%
4: 100.00%
5: 100.00%
6: 100.00%
7: 100.00%
8: 90.00%
9: 80.00%
10: 70.00%
題解:
對每一個節點作一次BFS,在以前的題中都是用一個bool數組儲存是否已經訪問過,此次則使用一個int數組(用來保存一個節點到另外一個節點的距離),初始將其設置爲-1,讀入原點時將其置爲0,每次做BFS,將該距離設置爲指向他的那個節點的距離+1,若是距離小於等於6就計數,到了大於6時直接退出,由於廣度優先搜索的特性,出現了距離大於6的節點後,以後全部的節點距咱們給定節點的距離都會大於6,因此就不用再繼續數去浪費時間了。
代碼:
#include <cstdio> #include <stdlib.h> #include <string.h> #include<stdbool.h> #define WeightType int #define MAXSIZE 1001 #define DataType int #define Vertex int #define ElementType Vertex using namespace std; int size; typedef struct QNode* Queue; struct QNode { ElementType Data[MAXSIZE]; int front; int rear; }; //Use the adjacency matrix to represent the graph typedef struct GNode* Graph; struct GNode { int Nvertex; int Nedge; WeightType graph[MAXSIZE][MAXSIZE]; DataType Data[MAXSIZE]; }; typedef struct ENode* Edge; struct ENode { Vertex begin; Vertex end; WeightType weight; }; //build edge Edge BuildEdge(Vertex begin, Vertex end, WeightType weight) { Edge e = (Edge)malloc(sizeof(struct ENode)); e->begin = begin; e->end = end; e->weight = weight; return e; } //creat empty graph Graph CreateGraph(int VertexNum) { Graph G = (Graph)malloc(sizeof(struct GNode)); G->Nvertex = VertexNum; G->Nedge = 0; for (int i = 0; i <= G->Nvertex; i++) { for (int j = 0; j <= G->Nvertex; j++) { G->graph[i][j] = 0; } } return G; } //insert edge void InsertEdge(Graph G, Edge e) { G->graph[e->begin][e->end] = e->weight; //If it is an undirected graph, you need to add the following G->graph[e->end][e->begin] = e->weight; G->Nedge++; } //build graph Graph BuildGraph() { int Nvertex, Nedge; scanf("%d %d", &Nvertex, &Nedge); size = Nvertex; Graph G = CreateGraph(Nvertex); for (int i = 0; i < Nedge; i++) { Vertex begin, end; WeightType weight; scanf("%d %d", &begin, &end); InsertEdge(G, BuildEdge(begin, end, 1)); } return G; } Queue makeempty() { Queue Q = (Queue)malloc(sizeof(struct QNode)); Q->front = 0; Q->rear = 0; return Q; } void QueueAdd(ElementType value, Queue ptrq) { if ((ptrq->rear + 1) % MAXSIZE == ptrq->front) { printf("The quque has been full."); return; } ptrq->rear = (++ptrq->rear) % MAXSIZE; ptrq->Data[ptrq->rear] = value; } ElementType QueueDelete(Queue ptrq) { if (ptrq->front == ptrq->rear) { printf("The queue has been empty."); return -1; } ptrq->front = (++ptrq->front) % MAXSIZE; return ptrq->Data[ptrq->front]; } bool isEmpty(Queue Q) { if (Q->front == Q->rear) { return true; } else { return false; } } //BFS int BFScountnum(Graph G, Vertex x, int dis[]) { //若是已經訪問過直接退出 dis[x] = 0; Queue Q = makeempty(); QueueAdd(x, Q); int sum = 1; while (!isEmpty(Q)) { Vertex v = QueueDelete(Q); for (int i = 1; i <= G->Nvertex; i++) { if (G->graph[v][i] != 0 && dis[i] == -1) { dis[i] = dis[v] + 1; if (dis[i] > 6) { break; } sum ++; QueueAdd(i, Q); } } } return sum; } int main() { Graph G = BuildGraph(); int dis[MAXSIZE]; for (int i = 1; i <= size; i++) { memset(dis, -1, sizeof(dis)); printf("%d: ",i); int sum = BFScountnum(G, i, dis); printf("%.2lf%%\n",((double)sum)/size*100); } return 0; }