最小生成樹算法

1.prim 類似於dijkstra 鬆弛就好  題目 51nod基礎題 無向圖最短生成樹
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <iostream>
#include <sstream>
#include <ostream>
#include <algorithm>
#include <ctype.h>
#include <cmath>
#include <queue>
#include <vector>
#define inf 1e9+7
#define pi acos(-1)
#define natrule exp(1)
using namespace std;
int g[1005][1005];
int d[1005];
bool used[1005];
long long prim(int n,int m)
{
    long long ans=0;
    d[1]=0;
    int now;
    while(true)
    {
        int mark=1;
        int maxx=inf;
        for(int i=1;i<=n;i++)
        {
            if(!used[i]&&d[i]<maxx) {
                maxx=d[i];
                now=i;
                mark=0;
            }
        }
        used[now]=true;
        for(int i=1;i<=n;i++)
        {
            if(!used[i]&&d[i]>g[now][i])
            {
                d[i]=g[now][i];
            }
        }
        if(mark) break;
    }
    for(int i=1;i<=n;i++) ans+=d[i];
    return ans;
}
int main()

{
    int n,m;
    cin>>n>>m;
    for(int i=0;i<1005;i++)
    {
        for(int j=0;j<1005;j++)
            g[i][j]=inf;
    }
    for(int i=0;i<1005;i++) d[i]=inf;
    for(int i=0;i<m;i++)
    {
        int s,e,value;
        cin>>s>>e>>value;
        g[s][e]=g[e][s]=value;
    }
    cout<<prim(n,m)<<endl;
    return 0;
}

堆優化

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <iostream>
#include <sstream>
#include <ostream>
#include <algorithm>
#include <ctype.h>
#include <cmath>
#include <queue>
#include <vector>
#define inf 1e9+7
#define pi acos(-1)
#define natrule exp(1)
using namespace std;
struct edge{
    int to,cost;
};//臨街表+G
typedef pair<int,int> P;//first 儲存最短距離 second 儲存的是編號 因爲greater 默認爲first升序排列
vector<edge> G[1005];
int used[1005];
int d[1005];
long long prim(int n,int m)
{
    priority_queue<P,vector<P>,greater<P> > qq;
    d[1]=0;
    qq.push(make_pair(0,1));
    long long ans=0;
    int cnt=1;
    while(!qq.empty())
    {
       // cout<<cnt++<<endl;
        P a=qq.top();
        qq.pop();
        if(used[a.second]) continue;
        used[a.second]=1;
        ans+=a.first;
        for(int i=0;i<G[a.second].size();i++)
        {
            edge eg=G[a.second][i];
            if(!used[eg.to]&&d[eg.to]>eg.cost)
            {
                d[eg.to]=eg.cost;
                P now;
                now.first=d[eg.to];
                now.second=eg.to;
                qq.push(now);
            }
        }
    }
    return ans;
}
int main(){
    int m,n;
    cin>>n>>m;
    for(int i=0;i<m;i++)
    {
        int s,e,value;
        cin>>s>>e>>value;
        edge k;
        k.to=e;
        k.cost=value;
        G[s].push_back(k);
        k.to=s;
        G[e].push_back(k);
    }
    for(int i=0;i<1005;i++) d[i]=inf;
    cout<<prim(n,m);
    return 0;
    
}
堆優化的時候由於圖不是稀疏圖 所以在小規模下優化也不是很明顯 第一個跑了158ms 堆優化竟然有140ms 

總結 :發現和dij驚人的相似 只不過鬆弛的時候不是到源點的距離的最小值 而是到沒有訪問過的點的最小邊長,同樣用堆優化 used判斷一下是否訪問過即可。

2.kruskal 算法 高效的並查集操作

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <iostream>
#include <sstream>
#include <ostream>
#include <algorithm>
#include <ctype.h>
#include <cmath>
#include <queue>
#include <vector>
#define inf 1e9+7
#define pi acos(-1)
#define natrule exp(1)
using namespace std;
int fa[1005];
int height[1005];
void init_union(int n)
{
    for(int i=0;i<n;i++)
    {
        fa[i]=i;
        height[i]=0;
    }
}
int find(int x)
{
    if(fa[x]==x) return x;
    else return fa[x]=find(fa[x]);
}
void unite(int x,int y)
{
    x=find(x);
    y=find(y);
    if(x==y) return ;
    if(height[x]<height[y])
        fa[x]=y;
    else
    {
        fa[y]=x;
        if(height[y]==height[x]) ++height[x];
    }
}
bool same(int x,int y)
{
    return find(x)==find(y);
}
struct edge{
    int s,e,w;
};
bool cmp(const edge& e1,const edge &e2)
{
    return e1.w<e2.w;
}
edge eg[50005];
int kruskal(int n,int m){
    sort(eg,eg+m,cmp);
    init_union(n);
    int res=0;
    for(int i=0;i<m;i++)
    {
        edge e=eg[i];
        if(!same(e.s,e.e)){
            unite(e.s,e.e);
            res+=e.w;
        }
    }
    return res;
}
int main()
{
    int n,m;
    cin>>n>>m;
    for(int i=0;i<m;i++)
    {
        int s,e,value;
        cin>>s>>e>>value;
        eg[i].s=s;
        eg[i].e=e;
        eg[i].w=value;
    }
    cout<<kruskal(n,m);
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章