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

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

ACM模板--邻接表 无向图 Prim Kruskal Dijkstra

發(fā)布時(shí)間:2025/6/15 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ACM模板--邻接表 无向图 Prim Kruskal Dijkstra 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.



/*** C++: Dijkstra算法獲取最短路徑(鄰接表)** @author judyge* @date 2014/04/24*/#include <iomanip> #include <iostream> #include <vector> using namespace std;// 示例類:邊的結(jié)構(gòu)體(用來(lái)演示) class EData {public:char start; // 邊的起點(diǎn)char end; // 邊的終點(diǎn)int weight; // 邊的權(quán)重public:EData(){}EData(char s, char e, int w):start(s),end(e),weight(w){} };// 鄰接表 class ListUDG { #define MAX 100 #define INF (~(0x1<<31)) // 最大值(即0X7FFFFFFF)private: // 內(nèi)部類// 鄰接表中表對(duì)應(yīng)的鏈表的頂點(diǎn)class ENode{int ivex; // 該邊所指向的頂點(diǎn)的位置int weight; // 該邊的權(quán)ENode *nextEdge; // 指向下一條弧的指針friend class ListUDG;};// 鄰接表中表的頂點(diǎn)class VNode{char data; // 頂點(diǎn)信息ENode *firstEdge; // 指向第一條依附該頂點(diǎn)的弧friend class ListUDG;};private: // 私有成員int mVexNum; // 圖的頂點(diǎn)的數(shù)目int mEdgNum; // 圖的邊的數(shù)目VNode mVexs[MAX];public:// 創(chuàng)建鄰接表對(duì)應(yīng)的圖(自己輸入)ListUDG();// 創(chuàng)建鄰接表對(duì)應(yīng)的圖(用已提供的數(shù)據(jù))ListUDG(char vexs[], int vlen, EData *edges[], int elen);~ListUDG();// 深度優(yōu)先搜索遍歷圖void DFS();// 廣度優(yōu)先搜索(類似于樹(shù)的層次遍歷)void BFS();// 打印鄰接表圖void print();// prim最小生成樹(shù)void prim(int start);// 克魯斯卡爾(Kruskal)最小生成樹(shù)void kruskal();// Dijkstra最短路徑void dijkstra(int vs, int vexs[], int dist[]);private:// 讀取一個(gè)輸入字符char readChar();// 返回ch的位置int getPosition(char ch);// 深度優(yōu)先搜索遍歷圖的遞歸實(shí)現(xiàn)void DFS(int i, int *visited);// 將node節(jié)點(diǎn)鏈接到list的最后void linkLast(ENode *list, ENode *node);// 獲取邊<start, end>的權(quán)值;若start和end不是連通的,則返回?zé)o窮大。int getWeight(int start, int end);// 獲取圖中的邊EData* getEdges();// 對(duì)邊按照權(quán)值大小進(jìn)行排序(由小到大)void sortEdges(EData* edges, int elen);// 獲取i的終點(diǎn)int getEnd(int vends[], int i); };/** 創(chuàng)建鄰接表對(duì)應(yīng)的圖(自己輸入)*/ ListUDG::ListUDG() {char c1, c2;int v, e;int i, p1, p2;int weight;ENode *node1, *node2;// 輸入"頂點(diǎn)數(shù)"和"邊數(shù)"cout << "input vertex number: ";cin >> mVexNum;cout << "input edge number: ";cin >> mEdgNum;if ( mVexNum < 1 || mEdgNum < 1 || (mEdgNum > (mVexNum * (mVexNum-1)))){cout << "input error: invalid parameters!" << endl;return ;}// 初始化"鄰接表"的頂點(diǎn)for(i=0; i<mVexNum; i++){cout << "vertex(" << i << "): ";mVexs[i].data = readChar();mVexs[i].firstEdge = NULL;}// 初始化"鄰接表"的邊f(xié)or(i=0; i<mEdgNum; i++){// 讀取邊的起始頂點(diǎn)和結(jié)束頂點(diǎn)cout << "edge(" << i << "): ";c1 = readChar();c2 = readChar();cin >> weight;p1 = getPosition(c1);p2 = getPosition(c2);// 初始化node1node1 = new ENode();node1->ivex = p2;node1->weight = weight;// 將node1鏈接到"p1所在鏈表的末尾"if(mVexs[p1].firstEdge == NULL)mVexs[p1].firstEdge = node1;elselinkLast(mVexs[p1].firstEdge, node1);// 初始化node2node2 = new ENode();node2->ivex = p1;node2->weight = weight;// 將node2鏈接到"p2所在鏈表的末尾"if(mVexs[p2].firstEdge == NULL)mVexs[p2].firstEdge = node2;elselinkLast(mVexs[p2].firstEdge, node2);} }/** 創(chuàng)建鄰接表對(duì)應(yīng)的圖(用已提供的數(shù)據(jù))*/ ListUDG::ListUDG(char vexs[], int vlen, EData *edges[], int elen) {char c1, c2;int i, p1, p2;int weight;ENode *node1, *node2;// 初始化"頂點(diǎn)數(shù)"和"邊數(shù)"mVexNum = vlen;mEdgNum = elen;// 初始化"鄰接表"的頂點(diǎn)for(i=0; i<mVexNum; i++){mVexs[i].data = vexs[i];mVexs[i].firstEdge = NULL;}// 初始化"鄰接表"的邊f(xié)or(i=0; i<mEdgNum; i++){// 讀取邊的起始頂點(diǎn)和結(jié)束頂點(diǎn)c1 = edges[i]->start;c2 = edges[i]->end;weight = edges[i]->weight;p1 = getPosition(c1);p2 = getPosition(c2);// 初始化node1node1 = new ENode();node1->ivex = p2;node1->weight = weight;// 將node1鏈接到"p1所在鏈表的末尾"if(mVexs[p1].firstEdge == NULL)mVexs[p1].firstEdge = node1;elselinkLast(mVexs[p1].firstEdge, node1);// 初始化node2node2 = new ENode();node2->ivex = p1;node2->weight = weight;// 將node2鏈接到"p2所在鏈表的末尾"if(mVexs[p2].firstEdge == NULL)mVexs[p2].firstEdge = node2;elselinkLast(mVexs[p2].firstEdge, node2);} }/* * 析構(gòu)函數(shù)*/ ListUDG::~ListUDG() { }/** 將node節(jié)點(diǎn)鏈接到list的最后*/ void ListUDG::linkLast(ENode *list, ENode *node) {ENode *p = list;while(p->nextEdge)p = p->nextEdge;p->nextEdge = node; }/** 返回ch的位置*/ int ListUDG::getPosition(char ch) {int i;for(i=0; i<mVexNum; i++)if(mVexs[i].data==ch)return i;return -1; }/** 讀取一個(gè)輸入字符*/ char ListUDG::readChar() {char ch;do {cin >> ch;} while(!((ch>='a'&&ch<='z') || (ch>='A'&&ch<='Z')));return ch; }/** 深度優(yōu)先搜索遍歷圖的遞歸實(shí)現(xiàn)*/ void ListUDG::DFS(int i, int *visited) {ENode *node;visited[i] = 1;cout << mVexs[i].data << " ";node = mVexs[i].firstEdge;while (node != NULL){if (!visited[node->ivex])DFS(node->ivex, visited);node = node->nextEdge;} }/** 深度優(yōu)先搜索遍歷圖*/ void ListUDG::DFS() {int i;int visited[MAX]; // 頂點(diǎn)訪問(wèn)標(biāo)記// 初始化所有頂點(diǎn)都沒(méi)有被訪問(wèn)for (i = 0; i < mVexNum; i++)visited[i] = 0;cout << "DFS: ";for (i = 0; i < mVexNum; i++){if (!visited[i])DFS(i, visited);}cout << endl; }/** 廣度優(yōu)先搜索(類似于樹(shù)的層次遍歷)*/ void ListUDG::BFS() {int head = 0;int rear = 0;int queue[MAX]; // 輔組隊(duì)列int visited[MAX]; // 頂點(diǎn)訪問(wèn)標(biāo)記int i, j, k;ENode *node;for (i = 0; i < mVexNum; i++)visited[i] = 0;cout << "BFS: ";for (i = 0; i < mVexNum; i++){if (!visited[i]){visited[i] = 1;cout << mVexs[i].data << " ";queue[rear++] = i; // 入隊(duì)列}while (head != rear) {j = queue[head++]; // 出隊(duì)列node = mVexs[j].firstEdge;while (node != NULL){k = node->ivex;if (!visited[k]){visited[k] = 1;cout << mVexs[k].data << " ";queue[rear++] = k;}node = node->nextEdge;}}}cout << endl; }/** 打印鄰接表圖*/ void ListUDG::print() {int i,j;ENode *node;cout << "List Graph:" << endl;for (i = 0; i < mVexNum; i++){cout << i << "(" << mVexs[i].data << "): ";node = mVexs[i].firstEdge;while (node != NULL){cout << node->ivex << "(" << mVexs[node->ivex].data << ") ";node = node->nextEdge;}cout << endl;} }/** 獲取邊<start, end>的權(quán)值;若start和end不是連通的,則返回?zé)o窮大。*/ int ListUDG::getWeight(int start, int end) {ENode *node;if (start==end)return 0;node = mVexs[start].firstEdge;while (node!=NULL){if (end==node->ivex)return node->weight;node = node->nextEdge;}return INF; }/** prim最小生成樹(shù)** 參數(shù)說(shuō)明:* start -- 從圖中的第start個(gè)元素開(kāi)始,生成最小樹(shù)*/ void ListUDG::prim(int start) {int min,i,j,k,m,n,tmp,sum;int index=0; // prim最小樹(shù)的索引,即prims數(shù)組的索引char prims[MAX]; // prim最小樹(shù)的結(jié)果數(shù)組int weights[MAX]; // 頂點(diǎn)間邊的權(quán)值// prim最小生成樹(shù)中第一個(gè)數(shù)是"圖中第start個(gè)頂點(diǎn)",因?yàn)槭菑膕tart開(kāi)始的。prims[index++] = mVexs[start].data;// 初始化"頂點(diǎn)的權(quán)值數(shù)組",// 將每個(gè)頂點(diǎn)的權(quán)值初始化為"第start個(gè)頂點(diǎn)"到"該頂點(diǎn)"的權(quán)值。for (i = 0; i < mVexNum; i++ )weights[i] = getWeight(start, i);for (i = 0; i < mVexNum; i++){// 由于從start開(kāi)始的,因此不需要再對(duì)第start個(gè)頂點(diǎn)進(jìn)行處理。if(start == i)continue;j = 0;k = 0;min = INF;// 在未被加入到最小生成樹(shù)的頂點(diǎn)中,找出權(quán)值最小的頂點(diǎn)。while (j < mVexNum){// 若weights[j]=0,意味著"第j個(gè)節(jié)點(diǎn)已經(jīng)被排序過(guò)"(或者說(shuō)已經(jīng)加入了最小生成樹(shù)中)。if (weights[j] != 0 && weights[j] < min){min = weights[j];k = j;}j++;}// 經(jīng)過(guò)上面的處理后,在未被加入到最小生成樹(shù)的頂點(diǎn)中,權(quán)值最小的頂點(diǎn)是第k個(gè)頂點(diǎn)。// 將第k個(gè)頂點(diǎn)加入到最小生成樹(shù)的結(jié)果數(shù)組中prims[index++] = mVexs[k].data;// 將"第k個(gè)頂點(diǎn)的權(quán)值"標(biāo)記為0,意味著第k個(gè)頂點(diǎn)已經(jīng)排序過(guò)了(或者說(shuō)已經(jīng)加入了最小樹(shù)結(jié)果中)。weights[k] = 0;// 當(dāng)?shù)趉個(gè)頂點(diǎn)被加入到最小生成樹(shù)的結(jié)果數(shù)組中之后,更新其它頂點(diǎn)的權(quán)值。for (j = 0 ; j < mVexNum; j++){// 獲取第k個(gè)頂點(diǎn)到第j個(gè)頂點(diǎn)的權(quán)值tmp = getWeight(k, j);// 當(dāng)?shù)趈個(gè)節(jié)點(diǎn)沒(méi)有被處理,并且需要更新時(shí)才被更新。if (weights[j] != 0 && tmp < weights[j])weights[j] = tmp;}}// 計(jì)算最小生成樹(shù)的權(quán)值sum = 0;for (i = 1; i < index; i++){min = INF;// 獲取prims[i]在矩陣表中的位置n = getPosition(prims[i]);// 在vexs[0...i]中,找出到j(luò)的權(quán)值最小的頂點(diǎn)。for (j = 0; j < i; j++){m = getPosition(prims[j]);tmp = getWeight(m, n);if (tmp < min)min = tmp;}sum += min;}// 打印最小生成樹(shù)cout << "PRIM(" << mVexs[start].data <<")=" << sum << ": ";for (i = 0; i < index; i++)cout << prims[i] << " ";cout << endl; }/* * 獲取圖中的邊*/ EData* ListUDG::getEdges() {int i,j;int index=0;ENode *node;EData *edges;edges = new EData[mEdgNum];for (i=0; i < mVexNum; i++){node = mVexs[i].firstEdge;while (node != NULL){if (node->ivex > i){edges[index].start = mVexs[i].data; // 起點(diǎn)edges[index].end = mVexs[node->ivex].data; // 終點(diǎn)edges[index].weight = node->weight; // 權(quán)index++;}node = node->nextEdge;}}return edges; }/* * 對(duì)邊按照權(quán)值大小進(jìn)行排序(由小到大)*/ void ListUDG::sortEdges(EData* edges, int elen) {int i,j;for (i=0; i<elen; i++){for (j=i+1; j<elen; j++){if (edges[i].weight > edges[j].weight){// 交換"邊i"和"邊j"swap(edges[i], edges[j]);}}} }/** 獲取i的終點(diǎn)*/ int ListUDG::getEnd(int vends[], int i) {while (vends[i] != 0)i = vends[i];return i; }/** 克魯斯卡爾(Kruskal)最小生成樹(shù)*/ void ListUDG::kruskal() {int i,m,n,p1,p2;int length;int index = 0; // rets數(shù)組的索引int vends[MAX]={0}; // 用于保存"已有最小生成樹(shù)"中每個(gè)頂點(diǎn)在該最小樹(shù)中的終點(diǎn)。EData rets[MAX]; // 結(jié)果數(shù)組,保存kruskal最小生成樹(shù)的邊EData *edges; // 圖對(duì)應(yīng)的所有邊// 獲取"圖中所有的邊"edges = getEdges();// 將邊按照"權(quán)"的大小進(jìn)行排序(從小到大)sortEdges(edges, mEdgNum);for (i=0; i<mEdgNum; i++){p1 = getPosition(edges[i].start); // 獲取第i條邊的"起點(diǎn)"的序號(hào)p2 = getPosition(edges[i].end); // 獲取第i條邊的"終點(diǎn)"的序號(hào)m = getEnd(vends, p1); // 獲取p1在"已有的最小生成樹(shù)"中的終點(diǎn)n = getEnd(vends, p2); // 獲取p2在"已有的最小生成樹(shù)"中的終點(diǎn)// 如果m!=n,意味著"邊i"與"已經(jīng)添加到最小生成樹(shù)中的頂點(diǎn)"沒(méi)有形成環(huán)路if (m != n){vends[m] = n; // 設(shè)置m在"已有的最小生成樹(shù)"中的終點(diǎn)為nrets[index++] = edges[i]; // 保存結(jié)果}}delete[] edges;// 統(tǒng)計(jì)并打印"kruskal最小生成樹(shù)"的信息length = 0;for (i = 0; i < index; i++)length += rets[i].weight;cout << "Kruskal=" << length << ": ";for (i = 0; i < index; i++)cout << "(" << rets[i].start << "," << rets[i].end << ") ";cout << endl; }/** Dijkstra最短路徑。* 即,統(tǒng)計(jì)圖中"頂點(diǎn)vs"到其它各個(gè)頂點(diǎn)的最短路徑。** 參數(shù)說(shuō)明:* vs -- 起始頂點(diǎn)(start vertex)。即計(jì)算"頂點(diǎn)vs"到其它頂點(diǎn)的最短路徑。* prev -- 前驅(qū)頂點(diǎn)數(shù)組。即,prev[i]的值是"頂點(diǎn)vs"到"頂點(diǎn)i"的最短路徑所經(jīng)歷的全部頂點(diǎn)中,位于"頂點(diǎn)i"之前的那個(gè)頂點(diǎn)。* dist -- 長(zhǎng)度數(shù)組。即,dist[i]是"頂點(diǎn)vs"到"頂點(diǎn)i"的最短路徑的長(zhǎng)度。*/ void ListUDG::dijkstra(int vs, int prev[], int dist[]) {int i,j,k;int min;int tmp;int flag[MAX]; // flag[i]=1表示"頂點(diǎn)vs"到"頂點(diǎn)i"的最短路徑已成功獲取。// 初始化for (i = 0; i < mVexNum; i++){flag[i] = 0; // 頂點(diǎn)i的最短路徑還沒(méi)獲取到。prev[i] = 0; // 頂點(diǎn)i的前驅(qū)頂點(diǎn)為0。dist[i] = getWeight(vs, i); // 頂點(diǎn)i的最短路徑為"頂點(diǎn)vs"到"頂點(diǎn)i"的權(quán)。}// 對(duì)"頂點(diǎn)vs"自身進(jìn)行初始化flag[vs] = 1;dist[vs] = 0;// 遍歷mVexNum-1次;每次找出一個(gè)頂點(diǎn)的最短路徑。for (i = 1; i < mVexNum; i++){// 尋找當(dāng)前最小的路徑;// 即,在未獲取最短路徑的頂點(diǎn)中,找到離vs最近的頂點(diǎn)(k)。min = INF;for (j = 0; j < mVexNum; j++){if (flag[j]==0 && dist[j]<min){min = dist[j];k = j;}}// 標(biāo)記"頂點(diǎn)k"為已經(jīng)獲取到最短路徑flag[k] = 1;// 修正當(dāng)前最短路徑和前驅(qū)頂點(diǎn)// 即,當(dāng)已經(jīng)"頂點(diǎn)k的最短路徑"之后,更新"未獲取最短路徑的頂點(diǎn)的最短路徑和前驅(qū)頂點(diǎn)"。for (j = 0; j < mVexNum; j++){tmp = getWeight(k, j);tmp = (tmp==INF ? INF : (min + tmp)); // 防止溢出if (flag[j] == 0 && (tmp < dist[j]) ){dist[j] = tmp;prev[j] = k;}}}// 打印dijkstra最短路徑的結(jié)果cout << "dijkstra(" << mVexs[vs].data << "): " << endl;for (i = 0; i < mVexNum; i++)cout << " shortest(" << mVexs[vs].data << ", " << mVexs[i].data << ")=" << dist[i] << endl; }int main() {int prev[MAX] = {0};int dist[MAX] = {0};// 頂點(diǎn)char vexs[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G'};// 邊EData *edges[] = {// 起點(diǎn) 終點(diǎn) 權(quán)new EData('A', 'B', 12), new EData('A', 'F', 16), new EData('A', 'G', 14), new EData('B', 'C', 10), new EData('B', 'F', 7), new EData('C', 'D', 3), new EData('C', 'E', 5), new EData('C', 'F', 6), new EData('D', 'E', 4), new EData('E', 'F', 2), new EData('E', 'G', 8), new EData('F', 'G', 9), };int vlen = sizeof(vexs)/sizeof(vexs[0]);int elen = sizeof(edges)/sizeof(edges[0]);ListUDG* pG;// 自定義"圖"(輸入矩陣隊(duì)列)//pG = new ListUDG();// 采用已有的"圖"pG = new ListUDG(vexs, vlen, edges, elen);//pG->print(); // 打印圖//pG->DFS(); // 深度優(yōu)先遍歷//pG->BFS(); // 廣度優(yōu)先遍歷//pG->prim(0); // prim算法生成最小生成樹(shù)//pG->kruskal(); // Kruskal算法生成最小生成樹(shù)// dijkstra算法獲取"第4個(gè)頂點(diǎn)"到其它各個(gè)頂點(diǎn)的最短距離pG->dijkstra(3, prev, dist);return 0; }

總結(jié)

以上是生活随笔為你收集整理的ACM模板--邻接表 无向图 Prim Kruskal Dijkstra的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。