最小生成树模板

  prim算法:

#include<bits/stdc++.h>
using namespace std;
//input by bxd
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define RI(n) scanf("%d",&(n))
#define RII(n,m) scanf("%d%d",&n,&m)
#define RIII(n,m,k) scanf("%d%d%d",&n,&m,&k)
#define RS(s) scanf("%s",s);
#define LL long long
#define REP(i,N)  for(int i=0;i<(N);i++)
#define CLR(A,v)  memset(A,v,sizeof A)
//////////////////////////////////
#define inf 900000r
#define N 1000
int n,m;
int ans;
int mp[N][N];
int vis[N];
struct edge
{
    int to;//to为通向的边
    int v;//为权值
    friend bool operator<(const edge& a,const edge& b)
    {
        return a.v>b.v;
    }
}now;

void prim(int s)
{
    vis[s]=1;
    priority_queue<edge>q;
    while(!q.empty())q.pop();

    rep(i,1,n)
    {
        rep(j,1,n)
        if(!vis[j])
        {
            now.to=j;
            now.v=mp[s][j];
            q.push(now);
        }
        while(!q.empty()&&vis[q.top().to])
            q.pop();
        if(q.empty())break;
        now=q.top();q.pop();
        s=now.to;
        ans+=now.v;
        vis[s]=1;
    }
}

int main()
{
    CLR(vis,0);
    RII(n,m);
    rep(i,1,n)
    rep(j,1,n)
    mp[i][j]=inf;
    while(m--)
    {
        int a,b,c;
        RIII(a,b,c);
        a++;b++;
        mp[a][b]=mp[b][a]=c;
    }
    prim(1);
    cout<<ans<<endl;
    return 0;
}
View Code

之前貌似学了假的prim   

下面给出更加普遍的写法  和dijkstra非常相似。。。  

    rep(i,1,n)
    dis[i]=inf;
    dis[1]=0;int u;
    rep(i,1,n)
    {
        double minn=1e8;
        rep(j,1,n)
        if(!vis[j]&&dis[j]<minn)
        minn=dis[u=j];
        ans+=minn;
        vis[u]=1;
        rep(j,1,n)
            if(dis[u]<dis[j])dis[j]=dis[u];
    }
View Code

prim:该算法的时间复杂度为O(n2)。与图中边数无关,该算法适合于稠密图。

kruskal:需要对图的边进行访问,所以克鲁斯卡尔算法的时间复杂度只和边又关系,可以证明其时间复杂度为O(eloge)。适合稀疏图。

第一个prim是经过堆优化过的   

其实并没有优化多少  只要记得稠密图用prim  稀疏图用kruskal即可

kruskal  注意一定要大一点的数组

struct node
{
    int s,e,v;
}s[100005];
int f[N];
int n,m;
int find1(int x)
{
  return f[x]==x?x:find1(f[x]);
}
bool cmp(node a,node b)
{
    return a.v<b.v;
}
int kruskal()
{
    int a,b,x=1;//一开始一定要是1
    int ans=0;
    sort(s+1,s+1+m,cmp);
    rep(i,1,m)
    {
        int a=find1(s[i].s);
        int b=find1(s[i].e);
        if(a==b)continue;
        ans+=s[i].v;
        f[a]=b;
        x++;
        if(x==n)return ans;//遍历了所有的点 是时候退出了
    }
    if(x!=n)return -1;//说明没有最小生成树
    else return ans;
}


int main()
{
    RII(n,m);
    rep(i,1,n)
    f[i]=i;
    rep(i,1,m)
    RIII(s[i].s,s[i].e,s[i].v);
    printf("%d
",kruskal());
}
View Code
原文地址:https://www.cnblogs.com/bxd123/p/10560965.html