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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

图论讲解(3)——最小生成树(基础)

發布時間:2024/9/21 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 图论讲解(3)——最小生成树(基础) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

關于這個東西,有的童鞋又要開始蒙了,最小生成樹是個什么鬼?!

前面我們已經說過樹是什么東西了,所謂最小生成樹嘛,最小嘛,那就是所有生成的樹中最小的那個唄!

太別扭了對吧?

好,我們來看看官方回答。

一個有 n 個結點的連通圖的生成樹是原圖的極小連通子圖,且包含原圖中的所有 n 個結點,并且有保持圖連通的最少的邊。最小生成樹可以用kruskal(克魯斯卡爾)算法或prim(普里姆)算法求出。

prim算法

Prim算法是通過先選取一個點,然后不斷加入點的一個過程。 ’初始化:V’={x},E’={},x是隨便一個節點; ’重復下列操作,直到V’=V: ? ′在E集合當中選擇最小的邊<u,v>使得u∈V’但是v?V’; ? ′V’加入節點v,E’加入<u,v>; ? ′(V’,E’)則為所求的最小生成樹。

′我們可以對該算法里面的各個步驟分別考慮: ′初始化:V’={x},E’={},x是隨便一個節點; ? ? ? ? ? ? ?這一步只需要隨便選取一個點即可; ′重復下列操作,直到V’=V: ′在E集合當中選擇最小的邊<u,v>使得u∈V’但是v?V’; ′V’加入節點v,E’加入<u,v>;       對于上面的第二步,實際上我們只需要對于每一個點維護一個V’集合中的點到達該點的最短距離。       然后每次掃描一遍數組找到我們所需要的v加入V’; 復雜度為O(N^2+M). 對于上面的第二步操作,我們實際上可以通過堆(優先隊列)維護一個滿足u∈V’但是v?V’的邊集,那么我們就能迅速取出滿足要求的邊; 然后當改變了V’的時候,我們就可以根據新加入的節點v對原有的堆進行刪除和插入操作。 需要注意的是,當我們用優先隊列實現的時候,我們需要將刪除操作延遲。 復雜度為O((N+M)logN). 嗶嗶了這么多,我們直接來看看代碼吧!(當然先是一些板子)

#include<bits/stdc++.h>
using namespace std;
const int maxn=10010;
int n,m,edge[maxn][maxn];
int dis[maxn];
bool boo[maxn];
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;++i){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
edge[x][y]=edge[y][x]=z;
}
dis[1]=0;
boo[1]=true;
for(int i=2;i<=n;++i)
dis[i]=123456789;
for(int i=2;i<=n;++i)
if(edge[1][i])
dis[i]=min(dis[i],edge[1][i]);
int ans=0;
for (int i=1;i<=n-1;++i)
{
int maxd=0;
for(int j=1;j<=n;++j)
{
if(!boo[j])
if(maxd==0||dis[maxd]>dis[j])
maxd=j;
}
boo[maxd]=true;
ans+=dis[maxd];
for(int j=1;j<=n;++j)
{
if(!boo[j])
if(edge[maxd][j])
dis[j]=min(dis[j],edge[maxd][j]);
}
}
printf("%d\n",ans);
return 0;
}

Kruskal算法 Kruskal算法主要分為兩步: 給所有邊按照邊權從小到大的順序排序; 從小到大依次考慮每條邊(u,v)(最開始沒有任何的邊): 如果u與v已經連通了,那么加入(u,v)后會出現環,不添加; 如果u與v沒有連通,那么加入(u,v)使其連通。 然后,對于判斷是否聯通,我們可以通過并查集來維護。

是不是感覺k算法比p算法好理解啊(暫且先那么叫)

據徐大佬說k算法好像比p算法快,唉,如果讓你寫的話,是不是一定選擇這種又快有好寫還有好理解的代碼啊。

反正讓我寫的的話,我一定會選擇寫k算法的,但是這僅限于裸地最小生成樹的題。

對于有的題k算法是不如p算法的,甚至有的時候,你用k算法還不一定能做出來。

好了,廢話不多說了,我們來看看代碼吧。

?

#include <bits/stdc++.h> using namespace std;const int maxn=100000+15; struct Edge {int x,y,z; }edge[maxn]; bool cmp(Edge a,Edge b) {return a.z<b.z; } int top[maxn],x,y,z,n,m; int found(int x) {if (top[x]==x) return x;top[x]=found(top[x]);return top[x]; } int main() {scanf("%d%d",&n,&m);for (int i=1;i<=m;i++){int x,y,z;scanf("%d%d%d",&x,&y,&z);edge[i].x=x;edge[i].y=y;edge[i].z=z;}sort(edge+1,edge+m+1,cmp);for (int i=1;i<=n;i++) top[i]=i;int ans=0;for (int i=1;i<=m;i++){int x=edge[i].x,y=edge[i].y;int fx=found(x),fy=found(y);if (fx==fy) continue;top[fx]=fy;ans+=edge[i].z;}printf("%d\n",ans);return 0; }

?

?

?

最小瓶頸生成樹

有的童鞋看到這個就要抓狂了,這又是個什么鬼!!!

哎呀,不要著急,我們來具體看一看這個東西。

最小瓶頸生成樹:在一個圖中找出一棵樹,使這棵樹的最大權值最小。

給你一個這樣的關系吧:最小生成樹一定是最小瓶頸生成樹,最小瓶頸生成樹不一定是最小生成樹。

最優比率生成樹

給出一個圖,每條邊的權值是(a,b)的形式。求出一個生成樹使得suma/sumb最小。 權值均為正值 ′二分答案 ′Suma/sumb>K ′Suma>Sumb*K, ′Sum(a-kb)>0 ′一般的最大生成樹 #include <bits/stdc++.h> using namespace std;const int maxn=100000+15; struct Edge {int x,y,a,b;Edge(int x=0,int y=0,int a=0,int b=0):x(x),y(y),a(a),b(b) {} }edge[maxn],edge2[maxn]; int mst() {return 0; } int change(int K) {for (int i=1;i<=m;i++)edge2[i]=Edge(edge[i].x,edge[i].y,edge[i].a-K*edge[i].b,0);return 0; } int main() {scanf("%d%d",&n,&m);for (int i=1;i<=m;i++){int x,y,a,b;scanf("%d%d%d%d",&x,&y,&a,&b);edge[i]=Edge(x,y,a,b);}int l=0,r=1000000,mid;while (l+1<r){mid=(l+r)/2;change(mid);if (mst()<=0) r=mid;else l=mid;}printf("%d\n",r);return 0; }

?

轉載于:https://www.cnblogs.com/z360/p/6853637.html

總結

以上是生活随笔為你收集整理的图论讲解(3)——最小生成树(基础)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。