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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

hdu 1233 还是畅通工程(最小生成树的Prim和Kruskal两种算法的c++实现)(prim算法详解)...

發(fā)布時間:2024/4/15 c/c++ 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 hdu 1233 还是畅通工程(最小生成树的Prim和Kruskal两种算法的c++实现)(prim算法详解)... 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

赤裸裸滴最小生成樹(MST),剛學(xué)的玩意,用兩種方法熟練一下。(都是greedy)

Kruskal方法:先對邊按照代價非遞減排序,再不斷添加邊且不產(chǎn)生環(huán)路,當(dāng)邊數(shù)=點數(shù)-1結(jié)束。判斷加入(v,w)是否會產(chǎn)生環(huán)路,可以用并查集,如果檢查v和w在同一集合中,說明這兩個點已經(jīng)連通,加入邊(v, w)就會產(chǎn)生環(huán)路。Kruskal算法總時間復(fù)雜度O(eloge).

1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 const int MAXN = 5050; 5 int n, father[MAXN], m; //m邊數(shù) 6 struct Edge 7 { 8 int x, y, length; 9 bool operator<(const Edge a) const 10 { 11 return length < a.length; 12 } 13 }; 14 Edge e[MAXN]; 15 void Init(int *a) 16 { 17 for (int i = 1; i <= n; ++i) 18 father[i] = i; 19 } 20 int Find(int x) 21 { 22 if (x != father[x]) 23 father[x] = Find(father[x]); 24 return father[x]; 25 } 26 void Union(int x, int y) 27 { 28 int fx = Find(x), fy = Find(y); 29 if (fx != fy) 30 father[fx] = fy; 31 } 32 int Kruskal() 33 { 34 std::sort(e, e + m); 35 Init(father); 36 int sum = 0; 37 for (int i = 0; i < m; ++i) 38 if (Find(e[i].x) != Find(e[i].y)) 39 { 40 Union(e[i].x, e[i].y); 41 sum += e[i].length; 42 } 43 return sum; 44 } 45 int main() 46 { 47 while (scanf("%d", &n) != EOF && n) 48 { 49 m = n * (n - 1) / 2; 50 for (int i = 0; i < m; ++i) 51 scanf("%d %d %d", &e[i].x, &e[i].y, &e[i].length); 52 printf("%d\n", Kruskal()); 53 } 54 return 0; 55 }

Prim算法:

1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 const int MAXN = 101; 5 const int INF = INT_MAX; 6 int n, m, visited[MAXN], dist[MAXN]; //dist[i]記錄i到與i鄰接且未被訪問的點的最小權(quán)值 7 int map[MAXN][MAXN]; 8 int Prim(int n) 9 { 10 memset(visited, 0, sizeof(visited)); 11 visited[1] = 1; 12 dist[1] = INF; 13 for (int i = 2; i <= n; ++i) 14 dist[i] = map[1][i]; 15 int min, pos, sum = 0; 16 for (int i = 2; i <= n; ++i) //加入剩下的n-1個點 17 { 18 min = INF; 19 for (int j = 1; j <= n; ++j) 20 if (!visited[j] && dist[j] < min) 21 { 22 min = dist[j]; 23 pos = j; 24 } 25 sum += min; //或者sum += dist[pos]; 26 visited[pos] = 1; 27 for (int j = 1; j <= n; ++j) //刷新最小權(quán)值 28 if (!visited[j] && map[pos][j] < dist[j]) 29 dist[j] = map[pos][j]; 30 } 31 return sum; 32 } 33 int main() 34 { 35 while (scanf("%d", &n) != EOF && n) 36 { 37 m = n * (n - 1) / 2; 38 int x, y, len; 39 for (int i = 0; i < m; ++i) //建圖 40 { 41 scanf("%d %d %d", &x, &y, &len); 42 map[x][y] = map[y][x] = len; 43 } 44 for (int i = 0; i <= n; ++i) 45 map[i][i] = INF; 46 printf("%d\n", Prim(n)); 47 } 48 return 0; 49 }

?

還不是很熟悉,貼一個資料先學(xué)一下。

假設(shè)G=(V,E)為一網(wǎng)圖,其中V 為網(wǎng)圖中所有頂點的集合,E 為網(wǎng)圖中所有帶權(quán)邊的集合。設(shè)置兩個新的集合U 和T,其中集合U 用于存放G 的最小生成樹中的頂點,集合T 存放G 的最小生成樹中的邊。令集合U 的初值為U={u1}(假設(shè)構(gòu)造最小生成樹時,從頂點u1 出發(fā)),集合T 的初值為T={}。Prim 算法的思想是,從所有u∈U,v∈V-U 的邊中,選取具有最小權(quán)值的邊(u,v),將頂點v 加入集合U 中,將邊(u,v)加入集合T 中,如此不斷重復(fù),直到U=V 時,最小生成樹構(gòu)造完畢,這時集合T 中包含了最小生成樹的所有邊。

Prim 算法可用下述過程描述,其中用wuv 表示頂點u 與頂點v 邊上的權(quán)值。
(1)U={u1},T={};
(2)while (U≠V)do
(u,v)=min{wuv;u∈U,v∈V-U }
T=T+{(u,v)}
U=U+{v}
(3)結(jié)束。
圖8.23 (a)所示的一個網(wǎng)圖,按照Prim 方法,從頂點1 出發(fā),該網(wǎng)的最小生成樹的產(chǎn)生過程如圖8.23 (b)、(c)、(d)、(e)、(f)和(g)所示。


為實現(xiàn)Prim 算法,需設(shè)置兩個輔助一維數(shù)組lowcost 和closevert,其中l(wèi)owcost 用來保存集合V-U 中各頂點與集合U 中各頂點構(gòu)成的邊中具有最小權(quán)值的邊的權(quán)值;數(shù)組closevertex 用來保存依附于該邊的在集合U 中的頂點。假設(shè)初始狀態(tài)時,U={u1}(u1 為出發(fā)的頂點),這時有l(wèi)owcost[0]=0,它表示頂點u1 已加入集合U 中,數(shù)組lowcost 的其它各分量的值是頂點u1 到其余各頂點所構(gòu)成的直接邊的權(quán)值。然后不斷選取權(quán)值最小的邊(ui,uk)(ui∈U,uk∈V-U),每選取一條邊,就將lowcost(k)置為0,表示頂點uk 已加入集合U 中。由于頂點uk 從集合V-U 進入集合U 后,這兩個集合的內(nèi)容發(fā)生了變化,就需依據(jù)具體情況更新數(shù)組lowcost 和closevertex 中部分分量的內(nèi)容。最后closevertex 中即為所建立的最小生成樹。

當(dāng)無向網(wǎng)采用二維數(shù)組存儲的鄰接矩陣存儲時,Prim 算法的C 語言實現(xiàn)為:

先從某一點開始,把這一個開始的點放于聲明的一個數(shù)組或者集合里,表明這一點已經(jīng)被訪問過。然后再從余下的n-1個點里去找那個權(quán)值最小的點并記錄該點的位置然后再加上這一點的權(quán)值,同時將該點放于集合里表明該點已初訪問。再更新權(quán)值

void Prim(int gm[][MAXNODE],int n,int closevertex[]) {/*用Prim 方法建立有n 個頂點的鄰接矩陣存儲結(jié)構(gòu)的網(wǎng)圖gm 的最小生成樹*/ /*從序號為0 的頂點出發(fā);建立的最小生成樹存于數(shù)組closevertex 中*/int lowcost[100],mincost;int i,j,k;for (i=1;i<n;i++) /*初始化*/{lowcost[i]=gm[0][i];closevertex[i]=0;}lowcost[0]=0; /*從序號為0 的頂點出發(fā)生成最小生成樹*/closevertex[0]=0;for (i=1;i<n;i++) /*尋找當(dāng)前最小權(quán)值的邊的頂點*/{mincost=MAXCOST; /*MAXCOST 為一個極大的常量值*/j=1;k=1;while (j<n){ if (lowcost[j]<mincost && lowcost[j]!=0){ mincost=lowcost[j];k=j;}j++;}printf(“頂點的序號=%d 邊的權(quán)值=%d\n”,k,mincost);lowcost[k]=0;for (j=1;j<n;j++) /*修改其它頂點的邊的權(quán)值和最小生成樹頂點序號*/if (gm[k][j]<lowcost[j]){ lowcost[j]=gm[k][j];closevertex[j]=k;}} }

?

算法8.14

圖8.24 給出了在用上述算法構(gòu)造網(wǎng)圖8.23 (a)的最小生成樹的過程中,數(shù)組closevertex、lowcost 及集合U,V-U 的變化情況,讀者可進一步加深對Prim 算法的了解。

在Prim 算法中,第一個for 循環(huán)的執(zhí)行次數(shù)為n-1,第二個for 循環(huán)中又包括了一個while 循環(huán)和一個for 循環(huán),執(zhí)行次數(shù)為2(n-1)2,所以Prim 算法的時間復(fù)雜度為O(n2)。

如果沒有看懂的話,再接著看下面這個比較通俗的:

關(guān)于prim算法

先把有的點放于一個集合(或者數(shù)組)里,這個集合里存放的是所有走過的點。初始值為0或者false表示還沒有點

聲明一個一維數(shù)組用于記錄各點的權(quán)值[可理解為起始點到目標(biāo)點的距離],

聲明一個二維數(shù)組用于記錄某點到某一點的權(quán)值,如果這兩點不可達到,則設(shè)置為無窮大

具體執(zhí)行過程:

先從某一點開始,把這一個開始的點放于聲明的一個數(shù)組或者集合里,表明這一點已經(jīng)被訪問過。然后再從余下的n-1個點里去找那個權(quán)值最小的點并記錄該點的位置然后再加上這一點的權(quán)值,同時將該點放于集合里表明該點已初訪問。再更新權(quán)值

再看下圖,從下圖分析:

1、

先選取一個點作起始點,然后選擇它鄰近的權(quán)值最小的點(如果有多個與其相連的相同最小權(quán)值的點,隨便選取一個)。如1作為起點。

isvisited[1]=1;?? //表明把1加進來說明是已經(jīng)訪問過

pos=1; //記錄該位置

//用dist[]數(shù)組不斷刷新最小權(quán)值,dist[i](0<i<=點數(shù))的值為:i點到鄰近點(未被標(biāo)記)的最小距離。

dist[1]=0;? //起始點i到鄰近點的最小距離為0

dist[2]=map[pos][2]=4;

dist[3]=map[pos][3]=2;

dist[4]==map[pos][4]=3;

dist[5]=map[pos][5]=MaxInt;? //無法直達

dist[6]=map[pos][6]=MaxInt;

?

2、

再在伸延的點找與它鄰近的兩者權(quán)值最小的點。

//dist[]以3作當(dāng)前位置進行更新

isvisited[3]=1;

pos=3;

dist[1]=0;?? //已標(biāo)記,不更新

dist[2]=map[pos][2]=4;??//比5小,不更新

dist[3]=2;? //已標(biāo)記,不更新

dist[4]=map[pos][4]=3;?? //比1大,更新

dist[5]=map[pos][5]=MaxInt;

dist[6]=map[pos][6]=MaxInt;

?

3、最后的結(jié)果:

?

當(dāng)所有點都連同后,結(jié)果最生成樹如上圖所示。

所有權(quán)值相加就是最小生成樹,其值為2+1+2+4+3=12。

prim算法的實現(xiàn):

[cpp]?view plaincopyprint?
  • //prim算法??
  • ??
  • int?prim(int?n){??
  • ??
  • ?????????int?i,j,min,pos;??
  • ??
  • ?????????int?sum=0;??
  • ??
  • ?????????memset(isvisited,false,sizeof(isvisited));??
  • ??
  • ???
  • ??
  • ?????????//初始化??
  • ??
  • ?????????for(i=1;i<=n;i++){??
  • ??
  • ???????????????????dist[i]=map[1][i];??
  • ??
  • ?????????}??
  • ??
  • ???
  • ??
  • ?????????//從1開始??
  • ??
  • ?????????isvisited[1]=true;??
  • ??
  • ?????????dist[1]=MAX;??
  • ??
  • ???
  • ??
  • ?????????//找到權(quán)值最小點并記錄下位置??
  • ??
  • ?????????for(i=1;i<n;i++){??
  • ??
  • ???????????????????min=MAX;??
  • ??
  • ???????????????????//pos=-1;??
  • ??
  • ???????????????????for(j=1;j<=n;j++){??
  • ??
  • ????????????????????????????if(!isvisited[j]?&&?dist[j]<min){??
  • ??
  • ?????????????????????????????????????min=dist[j];??
  • ??
  • ?????????????????????????????????????pos=j;??
  • ??
  • ????????????????????????????}??
  • ??
  • ???????????????????}??????????
  • ??
  • ???????????????????sum+=dist[pos];//加上權(quán)值??
  • ??
  • ???????????????????isvisited[pos]=true;??
  • ??
  • ???
  • ??
  • ???????????????????//更新權(quán)值??
  • ??
  • ???????????????????for(j=1;j<=n;j++){??
  • ??
  • ????????????????????????????if(!isvisited[j]?&&?dist[j]>map[pos][j]){??
  • ??
  • ?????????????????????????????????????dist[j]=map[pos][j];??
  • ??
  • ????????????????????????????}??
  • ??
  • ???????????????????}??
  • ??
  • ?????????}??????????
  • ??
  • ?????????return?sum; ???
  • }
  • ?

    轉(zhuǎn)載于:https://www.cnblogs.com/PegasusWang/archive/2013/04/29/3050783.html

    總結(jié)

    以上是生活随笔為你收集整理的hdu 1233 还是畅通工程(最小生成树的Prim和Kruskal两种算法的c++实现)(prim算法详解)...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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