1. 程式人生 > >最小生成樹 PRIM KRUSKAL

最小生成樹 PRIM KRUSKAL

SDUT 2144
與此題為例講一下prim演算法
簡要概括最短路和最小生成樹的區別
一句話概括:最小生成樹是計算從一節點到另一節點的最小邊集;最短路是帶權路徑,計算權值最小。也就是說,最小生成樹要經過每一個點,而最短路只需要能達到某兩點,路徑權值最小即可!(這句話摘自其他部落格)
prim的演算法內容和最短路的DJ演算法差不多

#include <bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
int tu[105][105];
int vis[105];
int mincost[105];//標記最小權值
int n; int prim() { memset(vis,0,sizeof(vis)); for(int i=1; i<=n; i++)//初始化從一開始到每個點的距離所以小於等於n { mincost[i]=tu[1][i]; } vis[1]=1; int ans=0; for(int i=2; i<=n; i++)//找剩餘的n-1個點 { int pos=i; int M=INF; for(int j=1; j<=n; j++) { if
(!vis[j]&&mincost[j]<M) { M=mincost[j]; pos=j; } } ans+=M; vis[pos]=1; for(int j=1; j<=n; j++)//鬆弛//更新從當前點到每個點的最短距離 { if(!vis[j]&&mincost[j]>tu[pos][j]) { mincost[j]=tu[pos][j]; } } } return
ans; } int main() { int m,j,k,l; while(~scanf("%d %d",&n,&m))//n為點數,m為邊數 { for(int i=1; i<=n; i++)//圖的預處理 for(int u=1; u<=n; u++) i==u?tu[i][u]=1:tu[i][u]=INF; for(int i=0; i<m; i++)//邊數 { scanf("%d %d %d",&j,&k,&l);//無向圖 if(tu[j][k]>l) { tu[j][k]=l; tu[k][j]=l; } } int x=prim(); printf("%d\n",x); } }

SDUT 2144

依舊是這道題目講一下kruskal

kruskal可以運用了並查集,,不懂得去學吧(但是如果你都開始做這類題了,並查集沒理由不會啊)

#include <bits/stdc++.h>
using namespace std;
struct node
{
    int u,v,w;
}tu[10005];
int p[1004],n,m;
bool cmp(node a,node b)
{
    return a.w<b.w;
}
int fing(int x)//找大哥
{
    return p[x]==x?x:p[x]=fing(p[x]);
}
void kruskal()
{
    int ans=0;
    int cnt=0;
    for(int i=1;i<=n;i++)//初始化並茶几陣列,以點為下標所以為點數n
        p[i]=i;
    for(int i=1;i<=m;i++)//按邊生成
    {
        int x=fing(tu[i].u),y=fing(tu[i].v);
        if(x!=y)
        {
            p[x]=y;
            ans+=tu[i].w;
            cnt++;
            if(cnt==n)//所有點都走完了退出
                break;
        }
    }
    printf("%d\n",ans);
}

int main()
{
    while(~scanf("%d %d",&n,&m))
    {
        for(int i=1; i<=m; i++)//俺邊數輸入
        {
            scanf("%d %d %d",&tu[i].u,&tu[i].v,&tu[i].w);
        }
        sort(tu+1,tu+m+1,cmp);//kruskal按照邊權的大小來查詢最小邊權
        kruskal();
    }
}