最小生成树模板&&总结--Prim&&Kruskal

一.最小生成树:连通N个点的边权值总和最小的树。

二.时间复杂度

Prim算法:时间复杂度O(|V|2+|E|),O(|E|log|V|)

Kruskal算法:时间复杂度O(|E|log|E|)

算法的选择: 从图的稀疏程度考虑(稠密图Prim,稀疏图Kruskal或Prim + Heap)

三.具体算法

  1.Prim算法:(1) 任意选定一点s,设集合S={s}

                       (2) 从不在集合S的点中选出一个点j使得其与S内的某点i的距离最短,则(i,j)就是生成树上的一条边,同时将j点加入S

                       (3) 转到(2)继续进行,直至所有点都己加入S集合

     Prim模板:

#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <stack>
#include <vector>
#define Twhile() int T;scanf("%d",&T);while(T--)
#define ArrInit(a,b,n) for(int i=0;i<=n;i++)a[i]=b
#define ArrInit2(a,b,n,m) for(int i=0;i<=n;i++)for(int j=0;j<=m;j++)a[i][j]=b
#define fora(i,a,b) for(int i=a;i<b;i++)
#define fors(i,a,b) for(int i=a;i>b;i--)
#define fora2(i,a,b) for(int i=a;i<=b;i++)
#define fors2(i,a,b) for(int i=a;i>=b;i--)
#define PI acos(-1.0)
#define eps 1e-6
#define INF 0x3f3f3f3f

typedef long long LL;
typedef long long LD;
using namespace std;
const int maxn=2000+11;
int ma[maxn][maxn];
int N,M;//点数,边数
int ans;//最小生成树的权值之和
//stack<int>S;  //最小生成树加入的点的顺序
//int lowerPoint[maxn]; // i离S中的lowerPoint[i]最近
int lowerCost[maxn],use[maxn];//lowerCost离S的最小距离,use是否被加入S
void init()
{
    ans=0;
    ArrInit2(ma,INF,N,N);
    ArrInit(use,0,N);
}
void primInit()
{
//    S.push(1);
    use[1]=1;
    lowerCost[1]=0;
//    lowerPoint[1]=1;
    fora2(i,2,N)
    {
//        lowerPoint[i]=1;
        lowerCost[i]=ma[1][i];
    }
}
void prim()
{
    primInit();
    int n=N-1;
    while(n--){
    int k=-1,tem=INF;
    fora2(i,2,N)//找到距离S集合最小的点
    {
        if(use[i])continue;
        if(lowerCost[i]<tem)
        {
            tem=lowerCost[i];
            k=i;
        }
    }
    use[k]=1;
    ans+=tem;
    /*
    lowerCost[k]=0;lowerPoint[i]=i;  //不更新的话,当要求输出最小生成树的边可以直接输出
    S.push(k);
    */
    fora2(i,1,N)
    {
        if(use[i])continue;
        int t=ma[i][k];
        if(t<lowerCost[i])
        {
            lowerCost[i]=t;
            //lowerPoint[i]=k;
        }
    }
    if(tem==INF)return;//图不连通
    }
}

int main()
{

    while(~scanf("%d",&N)&&N)
    {
        scanf("%d",&M);
        init();
        while(M--)
        {
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            ma[x][y]=min(ma[x][y],z);
            ma[y][x]=min(ma[y][x],z);
        }
        if(N==1){printf("0\n");continue;}
        prim();
        printf("%d\n",ans);
    }
    return 0;
}

例子:UVALive - 2515 Networking

     UVA - 10369

 2.Kruskal算法:(1) 将边按权值从小到大排序后逐个判断,如果当前的边加入以后不会产生环,那么就把当前边作为生成树的一条边

         (2) 最终得到的结果就是最小生成树

 Kruskal模板:

#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <stack>
#include <vector>
#define Twhile() int T;scanf("%d",&T);while(T--)
#define ArrInit(a,b,n) for(int i=0;i<=n;i++)a[i]=b
#define ArrInit2(a,b,n,m) for(int i=0;i<=n;i++)for(int j=0;j<=m;j++)a[i][j]=b
#define fora(i,a,b) for(int i=a;i<b;i++)
#define fors(i,a,b) for(int i=a;i>b;i--)
#define fora2(i,a,b) for(int i=a;i<=b;i++)
#define fors2(i,a,b) for(int i=a;i>=b;i--)
#define PI acos(-1.0)
#define eps 1e-6
#define INF 0x3f3f3f3f

typedef long long LL;
typedef long long LD;
using namespace std;
const int maxn=5000+11;
int N,M,ans;//点,边,最小生成树
struct edge
{
    int u,v;//点u到v
    int var;//权值
}ma[maxn];
bool cmp(edge a,edge b)
{
    return a.var<b.var;
}
int fa[maxn];
void initKruskal()
{
    ans=0;
    fora2(i,1,N)
    {
        fa[i]=i;
    }
    sort(ma+1,ma+M+1,cmp);

}
/*
Kruskal算法
(1) 将边按权值从小到大排序后逐个判断,如果当前的边加入以后不会产生环,那么就把当前边作为生成树的一条边
(2) 最终得到的结果就是最小生成树
并查集
*/
int findx(int x)
{
    if(x==fa[x])return x;
    return fa[x]=findx(fa[x]);
}
bool unio(int x,int y)
{
    int fx=findx(x),fy=findx(y);
    if(fx==fy)return false;
    fa[fy]=fx;
    return true;
}
void kruskal()
{
    initKruskal();
    int m=0;
    fora2(i,1,M)
    {
        if(unio(ma[i].u,ma[i].v))
        {
            m++;
            ans+=ma[i].var;
            //printf("%d %d  %d\n",ma[i].u,ma[i].v,m);
        }
        if(m==N-1)return;
    }
}

例子:UVALive - 2515 Networking

            I - Kruskal+一点性质 UVALive - 6837There is No Alternative

             J - 最小瓶颈路 UVA - 534 Frogger

猜你喜欢

转载自blog.csdn.net/liyang__abc/article/details/81563236