次小生成樹

2021-07-31 05:33:49 字數 3139 閱讀 2554

最小生成樹與次小生成樹

我們都知道要求最小生成樹有兩種方法可求,分別是prim演算法和kruskal演算法

1.prim演算法

設圖g =(v,e),其生成樹的頂點集合為u。

①、把v0放入u。

②、在所有u∈u,v∈v-u的邊(u,v)∈e中找一條最小權值的邊,加入生成樹。

③、把②找到的邊的v加入u集合。如果u集合已有n個元素,則結束,否則繼續執行②。

2.kruskal演算法

首先將所有邊按邊權排序,然後按照邊權從小到大依次處理.這裡要用到並查集的思想,假設已有點集u,現在正在處理邊i->j,如果i,j已在

u中則處理下一條邊,否則將i,j加入並查集中.繼續處理下一條邊,直到有n-1條邊為止.

3 次小生成樹

次小生成樹可由最小生成樹換一條邊得到

演算法:1)先用prim求出最小生成樹t,在prim的同時,用乙個矩陣max[u][v]記錄在樹中連線u-v的路徑中權值最大的邊.

2)列舉所有不在t中的邊u-v,加入邊u-v,刪除權值為max[u][v]的邊,不斷列舉找到次小生成樹.

下面給出次小生成樹的模板

#include#include#includeusing namespace std;

const int inf=0x3f3f3f3f;

int g[110][110],dist[110],mmax[110][110]; ///g儲存地圖 dist儲存從起點到其餘各點的距離 maxn儲存從i到j的最大邊權值

int pre[110]; ///pre儲存j的離它最近的是哪個點

bool mark[110]; ///相當於vis 用來標記該點是否已經用過

bool connect[110][110]; ///儲存i-j的那條邊是否加入了最小生成樹 false 加入 true 沒有

int mst,mint; ///mst儲存最小生成樹的權值和

int n,m;

int prim()

dist[1]=0;

mark[1]=true;

for(i=1;immax[j][fa])?mmax[fa][p]:mmax[j][fa];

for(j=1;j<=n;j++)}}

return res;

}int main()

mst=prim();

int i,j;

bool flag=false;

for(i=1;i<=n;i++)

for(j=1;j<=n;j++)

}if(flag)

printf("not unique!\n");

else

printf("%d\n",mst);

}return 0;

}

下面來一道題練練手

題意:題目大意:

有n個城市,秦始皇要修用n-1條路把它們連起來,要求從任一點出發,都可以到達其它的任意點。秦始皇希望這所有n-1條路長度之和最短。然後徐福突然有冒出來,說是他有魔法,可以不用人力、財力就變出其中任意一條路出來。

秦始皇希望徐福能把要修的n-1條路中最長的那條變出來,但是徐福希望能把要求的人力數量最多的那條變出來。對於每條路所需要的人力,是指這條路連線的兩個城市的人數之和。

最終,秦始皇給出了乙個公式,a/b,a是指要徐福用魔法變出的那條路所需人力, b是指除了徐福變出來的那條之外的所有n-2條路徑長度之和,選使得a/b值最大的那條。

分析與總結

為了使的a/b值最大,首先是需要是b盡量要小,所以可先求出n個城市的最小生成樹。然後,就是決定要選擇那一條用徐福的魔法來變。

因此,可以列舉每一條邊,假設最小生成樹的值是minmst, 而列舉的那條邊長度是w[i][j],  如果這一條邊已經是屬於最小生成樹上的,那麼最終式子的值是a/(minmst-w[i][j])。如果這一條不屬於最小生成樹上的, 那麼新增上這條邊,就會有n條邊,那麼就會使得有了乙個環,為了使得它還是乙個生成樹,就要刪掉環上的一棵樹。 為了讓生成樹盡量少,那麼就要刪掉除了加入的那條邊以外,權值最大的那條路徑。 假設刪除的那個邊的權值是path[i][j], 那麼就是a/(minmst-path[i][j]).

解這題的關鍵也在於怎樣求出次小生成樹。

ac**:

#include #include #include #include #include #define inf 0x3f3f3f3f

#define max 1010

using namespace std;

double map[max][max], dis[max], maxn[max][max]; ///map陣列儲存地圖 dis儲存從起點到其他點的距離 maxn儲存i到j的最大權值

int pre[max], vis[max];

bool used[max][max];

int n;

struct edge

edge[max];

double cal(edge a, edge b)

double prim()

vis[1] = 1;

int k;

for(int i = 1; i < n; i++)

}if(minn == inf) return -1;

vis[k] = 1;

ret+=minn;

father = pre[k];

used[father][k] = used[k][father] = 1;

maxn[father][k] = minn;

for(int j = 1; j <= n; j++)

for(int j = 1; j <= n; j++)}}

return ret;

}int main()

map[i][i] = 0;

}for(int i = 1; i <= n; i++)

for(int i = 1; i <= n; i++)

}double ans = prim();

double ans1 = -1;

for(int i = 1; i<= n; i++)}}

printf("%.2lf\n",ans1);

}return 0;

}

最小生成樹 次小生成樹

一 最小生成樹 說到生成樹首先要解釋一下樹,樹是乙個聯通的無向無環圖,多棵樹的集合則被稱為森林。因此,樹具有許多性質 1.兩點之間的路徑是唯一的。2.邊數等於點數減一。3.連線任意兩點都會生成乙個環。對於乙個無向聯通圖g的子圖,如果它包含g的所有點,則它被稱為g的生成樹,而各邊權和最小的生成樹則被稱...

次小生成樹

演算法引入 設g v,e,w 是連通的無向圖,t是圖g的一棵最小生成樹 如果有另一棵樹t1,滿足不存在樹t t t1 則稱t1是圖g的次小生成樹 演算法思想 鄰集的概念 由t進行一次可行交換得到的新的生成樹所組成的集合,稱為樹t的鄰集,記為n t 設t是圖g的最小生成樹,如果t1滿足 t1 min,...

次小生成樹

分類 圖論 2013 02 12 15 03 32人閱讀收藏 舉報次小生成樹 在求最小生成樹時,用陣列path i j 來表示mst中i到j最大邊權。求完後,直接列舉所有不在mst中的邊,把它加入到mst中構成一棵新的樹,且該樹有環,此環是由剛加入的邊 i,j 造成的,所以可以通過刪除path i ...