求無向連通圖的最小生成樹(c語言版)
完整原始碼地址:[email protected]:hglspace/MinCostSpTree.git
圖例:
1 普里姆演算法
/*
普里姆演算法:假設N={v,{E}}是連通圖,TE是N上的最小生成樹中邊的集合,演算法從U={u0}(u0屬於V),TE={}開始,重複執行下述操作:
在所有u屬於U,v屬於V-U的邊<u0,v0>屬於E中找一條代價最小的邊(u0,v0)併入集合TE,直至U=V為止,此時TE中必有n-1條邊,則T={V,{TE}}為N的最小生成樹
*/
void MiniSpanTree_PRIM(structGraph
struct tmp closedge[MAX_VEX_NUM];
int index=u.index,i,j;
int minimum(structtmp closedge[]);
for(j=0;j<g.vexnum;j++){//初始化輔助陣列,輔助陣列是記錄從U到V-U具有最小代價的邊
if(j!=index){
closedge[j].lowcost=g.arcs[index][j].cost;
closedge[j].vex=u;
}
}
closedge[index].lowcost=0;//自己到自己的最小權值是0
for(i=1;i<g.vexnum;i++){
index=minimum(closedge);
if(index<0){
printf("此圖不是連通圖\n");
exit(0);
}
printf("下一個頂點是:%c,權值是:%d\n",g.vexs[index].data,closedge[index].lowcost);
closedge[index].lowcost
for(j=0;j<g.vexnum;j++){//U中有增加了新頂點,比較closedge陣列中的最小權值和該頂點到V-U其他頂點的權值
if(g.arcs[index][j].cost<closedge[j].lowcost){
closedge[j].lowcost=g.arcs[index][j].cost;
closedge[j].vex=g.vexs[index];
}
}
}
}
int minimum(structtmp closedge[]){//求closedge陣列中最小權值的邊,返回V-U中的頂點位置
int i,tlow=999,index=-1;
for(i=0;i<MAX_VEX_NUM;i++){
if(tlow>closedge[i].lowcost && closedge[i].lowcost>0){
tlow=closedge[i].lowcost;
index=i;
}
}
return index;
}
2 克魯斯卡爾演算法
/*
克魯斯卡爾:假設連通圖N={v,{E}},則令最小生成樹的初始狀態為只有n個頂點而無邊的非連通圖T={v,{}},圖中每個頂點自稱一個連通分量。在E中選擇代價最小的邊,
若該邊依附的頂點落在T中不同的連通分量上,則將此邊加入到T中,否則捨去此邊而選擇下一條代價最小的邊。以此類推,直至T中所有的頂點都在同一連通分量上為止。
*/
void MiniSpanTree_KRUSKAL(structGraph g){//把當前圖用鄰接多重連結串列儲存?
//把鄰接矩陣結構儲存的圖轉化為鄰接多重連結串列結構,原因是:方便下面查詢兩個頂點是否在同一個連通圖中,並且會多次遍歷查詢
int i,j,n=1;
struct arc getMinArc(structGraph * g,structAmGraph amg);
struct arc a;
struct AmGraph amg={};
for(i=0;i<g.vexnum;i++){
struct VexBox v;
v.data=g.vexs[i].data;
v.firstedge=NULL;
v.mark=False;
amg.vb[i]=v;
}//初始化後,所有的頂點都是孤立的,並沒有任何邊
//按照定義開始選擇邊
while(n<g.vexnum){//最小生成樹的邊,必定比頂點數少一個
struct Ebox * e=(structEbox *)malloc(sizeof(structEbox));
a=getMinArc(&g,amg);//把找到的邊存放到多重連結串列結構的圖中
e->cost=a.cost;
e->ivex=a.head;
e->jvex=a.tail;
e->ilink=NULL;
e->jlink=NULL;
e->mark=False;
//把a新增到amg中
if(amg.vb[a.head].firstedge==NULL){
amg.vb[a.head].firstedge=e;
}else{
e->ilink=amg.vb[a.head].firstedge;
amg.vb[a.head].firstedge=e;
}
if(amg.vb[a.tail].firstedge==NULL){
amg.vb[a.tail].firstedge=e;
}else{
e->jlink=amg.vb[a.tail].firstedge;
amg.vb[a.tail].firstedge=e;
}
n++;
}
for(i=0;i<g.vexnum-1;i++){
for(j=i+1;j<g.vexnum;j++){
if(g.arcs[i][j].cost==0){//找到合適的邊,會把其權值置為0,這裡根據這個特點輸出
printf("頭頂點:%c,尾頂點:%c,權值是:%d\n",g.vexs[i].data,g.vexs[j].data,g.arcs[i][j].tmpcost);
}
}
}
}
/*
獲取合適的邊
*/
struct arc getMinArc(structGraph * g,structAmGraph amg){
int i,j,head,tail,tmp=999;
struct arc a;
Bool judgeLt(int head,int tail,structAmGraph g);
for(i=0;i<g->vexnum-1;i++){
for(j=i+1;j<g->vexnum;j++){
if(g->arcs[i][j].cost>0 && tmp>g->arcs[i][j].cost){
head=g->arcs[i][j].head;
tail=g->arcs[i][j].tail;
Vexflag=False;//在每次呼叫判斷兩個頂點是否在同一連通分量的方法之前,一定要把全域性變數Vexflag置為False,排除上一次查詢的結果的干擾
if(judgeLt(head,tail,amg)){
continue;
}
tmp=g->arcs[i][j].cost;
a=g->arcs[i][j];
}
}
}
g->arcs[a.head][a.tail].tmpcost=g->arcs[a.tail][a.head].tmpcost=a.cost;
g->arcs[a.head][a.tail].cost=g->arcs[a.tail][a.head].cost=0;
return a;
}
/*
判斷該邊依附的兩個頂點是否在同一連通分量上
*/
Bool judgeLt(int head,int tail,structAmGraph g){
//遍歷該圖,判斷這兩個頂點是否在一個連通分量上
Bool DFSTree(structAmGraph g,int v1,int v2,structEbox * ebs[]);
struct Ebox * ebs[MAX_EDG_NUM]={};
int i;
Bool flag=DFSTree(g,head,tail,ebs);
//一定要把amg的邊的mark再置為False,下次再呼叫,mark還是預設值,每次查詢,多重連結串列圖都應該是原始的,標誌變數一定要改回原來的狀態
for(i=0;ebs[i]!=NULL;i++){
ebs[i]->mark=False;
}
return flag;
}
Bool DFSTree(structAmGraph g,int v1,int v2,structEbox * ebs[]){
int i;
int getAdjVex(structAmGraph * g,int v,structEbox * ebs[]);
for(i=getAdjVex(&g,v1,ebs);i>0;i=getAdjVex(&g,v1,ebs)){
if(!g.vb[i].mark){//其實這個判斷不加也行,加這個判斷主要是排除兩個頂點之間有迴路的情況,而現在的情況是這兩個頂點之間不會有迴路的
g.vb[i].mark=True;
if(i==v2){
Vexflag=True;
}
}
DFSTree(g, i, v2,ebs);
}
returnVexflag;
}
/*
獲取該頂點的鄰接頂點
*/
int getAdjVex(structAmGraph * g,int v,structEbox * ebs[]){
int i;
for(i=0;ebs[i]!=NULL;i++);
struct Ebox * e=g->vb[v].firstedge;
if(e==NULL){
return -1;
}
for(;e!=NULL&&e->mark==True;){
if(e->ivex==v){
e=e->ilink;
}else{
e=e->jlink;
}
}
if(e==NULL){
return -1;
}else{
ebs[i]=e;//把遍歷過的邊,放在esb陣列中,呼叫結束後,把該邊的狀態置為原始值
e->mark=True;
if(e->ivex==v){
return e->jvex;
}else{
return e->ivex;
}
}
}
相關推薦
求無向連通圖的最小生成樹(c語言版)
完整原始碼地址:[email protected]:hglspace/MinCostSpTree.git 圖例: 1 普里姆演算法 /* 普里姆演算法:假設N={v,{E}}是連通圖,TE是N上的最小生成樹中邊的集合
求無向連通圖的最小割點詳解以及java原始碼實現
import java.util.*; /**尋找割點*/ public class FindArt { static class Node { Node(String name) { this.name=name; Childen=new Arra
求無向連通圖的割點
1. 割點與連通度 在無向連通圖中,刪除一個頂點v及其相連的邊後,原圖從一個連通分量變成了兩個或多個連通分量,則稱頂點v為割點,同時也稱關節點(Articulation Point)。一個沒有關節點的連通圖稱為重連通圖(biconnected graph)。若在連通圖上
【圖論】求無向連通圖的割點
1. 割點與連通度 在無向連通圖中,刪除一個頂點v及其相連的邊後,原圖從一個連通分量變成了兩個或多個連通分量,則稱頂點v為割點,同時也稱關節點(Articulation Point)。一個沒有關節點的連通圖稱為重連通圖(biconnected graph)。若在連通圖上至少刪去k 個頂點才能破壞圖的連通性,則
用Tarjan演算法求無向連通圖割點&&割邊
/** 割點割邊挺好理解的,割點就是一個無向連通圖,把其中一個點 挖掉剩下的圖不連通,割邊就是把一條邊砍掉不連通 比如:有一個通訊網路,要求一顆炸彈,把這個通訊網路搞得不連通,問 炸哪個點或哪條邊。 Tarjan 演算法實現求割邊
所有邊權均不相同的無向圖最小生成樹是唯一的證明
eight weight nbsp 不同的 權重 cnblogs 成了 http 方法 設G是所有邊權均不相同的無向聯通圖。 證明一: 首先,易證圖G中權值最小的邊一定是最小生成樹中的邊。(否則最小生成樹加上權值最小的邊後構成一個環,去掉環中任意一條非此邊則形成了另一
1212 無向圖最小生成樹
alt 時間 難度 布爾 too 數組 star tar += 1212 無向圖最小生成樹 基準時間限制:1 秒 空間限制:131072 KB 分值: 0 難度:基礎題 收藏 關註 N個點M條邊的無向連通圖,每條邊有一個權值,求該圖的最小生成樹。 In
51 nod 1212 無向圖最小生成樹(Kruckal演算法/Prime演算法圖解)
1212 無向圖最小生成樹 N個點M條邊的無向連通圖,每條邊有一個權值,求該圖的最小生成樹。 收起 輸入 第1行:2個數N,M中間用空格分隔,N為點的數量,M為邊的數量。(2 <= N <= 1000, 1 <= M <= 50000) 第2 -
51nod 1212 無向圖最小生成樹
數量 color def main tdi ring () return print N個點M條邊的無向連通圖,每條邊有一個權值,求該圖的最小生成樹。 輸入 第1行:2個數N,M中間用空格分隔,N為點的數量,M為邊的數量。(2 <= N &l
(圖論)51NOD 1212 無向圖最小生成樹
N個點M條邊的無向連通圖,每條邊有一個權值,求該圖的最小生成樹。 輸入 第1行:2個數N,M中間用空格分隔,N為點的數量,M為邊的數量。(2 <= N <= 1000, 1 <= M <= 50000) 第2 - M + 1
51Nod1212 無向圖最小生成樹
#include<iostream> #include<cstring> #include<cstdio> using namespace std; int map[
51nod 1212 無向圖最小生成樹(Kruskal演算法)
收藏 關注 N個點M條邊的無向連通圖,每條邊有一個權值,求該圖的最小生成樹。 Input 第1行:2個數N,M中間用空格分隔,N為點的數量,M為邊的數量。(2 <= N <= 1000, 1 <= M <= 5
51nod 1212 無向圖最小生成樹(最小生成樹)
收藏 關注 N個點M條邊的無向連通圖,每條邊有一個權值,求該圖的最小生成樹。 Input 第1行:2個數N,M中間用空格分隔,N為點的數量,M為邊的數量。(2 &
無向圖最小生成樹(prim演算法)
輸入 第1行:2個數N,M中間用空格分隔,N為點的數量,M為邊的數量。(2 <= N <= 1000, 1 <= M <= 50000) 第2 - M + 1行:每行3個數
51nod 1212 無向圖最小生成樹prim演算法
N個點M條邊的無向連通圖,每條邊有一個權值,求該圖的最小生成樹。 Input 第1行:2個數N,M中間用空格分隔,N為點的數量,M為邊的數量。(2 <= N <= 1000
leetcode 847. Shortest Path Visiting All Nodes 無向連通圖遍歷最短路徑
sel shu turn 判斷 lam 最短 額外 動態 訪問 設計最短路徑 用bfs 天然帶最短路徑 每一個狀態是 當前的階段 和已經訪問過的節點 下面是正確但是超時的代碼 class Solution: def shortestPathLength(self,
[帶標號無向連通圖計數 容斥原理 多項式求逆 多項式求ln 模板題] BZOJ 3456 城市規劃
可以通過容斥求出答案的表示式fi=2C2i−∑j=1i−1Cj−1i−1∗fj∗2C2i−j 其中前一部分表示i個點任意連邊 後半部分列舉1所在的連通塊然後容斥掉 ∑j=1ifj(j−1)!∗2C2i−j(i−j)!=2C2i(i−1)! 這是個卷積的
有向圖最小生成樹
基礎:無向圖的kruskal演算法 摘抄: 最 小樹形圖,就是給有向帶權圖中指定一個特殊的點root,求一棵以root為根的有向生成樹T,並且T中所有邊的總權值最小。最小樹形圖的第一個演算法是 1965年朱永津和劉振巨集提出的複雜度為O(VE)的演算法。 判斷是否存在樹形圖
有向圖最小生成樹——最小樹形圖(朱…
對於有向圖的最小生成樹 , 也叫做最小樹形圖 。 最小樹形圖的第一個演算法是1965年朱永津和劉振巨集提出的複雜度為O(VE)的演算法。 值得我們驕傲啊 。 下面來分享這個演算法 。 1、求最小樹形圖之前一定要確定根 , 確定根之後再去驗證是否存在樹形圖(這個很簡單 , 就是從根節點能不能到其他點)
poj1523 SPF 無向連通圖 求割點 關節點 tarjan演算法
SPF Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 5103 Accepted: 2347 Description Consider the two networks shown below.