zoukankan      html  css  js  c++  java
  • 最小生成树Prim算法 Kruskal算法

    Prim算法(贪心策略)N^2

    选定图中任意定点v0,从v0开始生成最小生成树

    树中节点Va,树外节点Vb

    最开始选一个点为Va,其余Vb,

    之后不断加Vb到Va最短距离的点

    1.初始化d[v0]=0,其他d[i]=正无穷。d表示Vb电到i的最小距离

    2.经过n次如下步骤,得到一颗喊n节点n-1边的最小生成树

    (1)选择一个未标记的k,并且d[k]的值最小

    (2)标记点k进入树Va

    (3)以k为中间点,修改未标记的点j,即Vb中的点到Va的距离值;

    3.得到最小生成树t

    #include<iostream>
    #include<iomanip> 
    #include<cstring>
    using namespace std;
    const int INF=0x7fffffff/2;
    int vst[505];//标记i是否加入最小生成树Va中 
    int d[505];//i与当前生成树中的点有连边的边长最小值 
    int g[505][505],n,m,ans=0;//g存边和权值 
    void read(){//读入数据 
        int i,j,x,y,w;
        cin>>n>>m;//n点m边 
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
            g[i][j]=INF;//清零 
        for(i=1;i<=m;i++){
            cin>>x>>y>>w;
            g[x][y]=g[y][x]=w;//记录边和权值 
        }
    }
    void prim(int v0){
        int i,j,k,minn;
        memset(vst,0,sizeof(vst));
        for(i=1;i<=n;i++) d[i]=INF;//初始化 
        d[v0]=0;//最初节点 
        ans=0;
        for(i=1;i<=n;i++){//选择n个点 
            minn=INF;
            for(j=1;j<=n;j++)//选择最小边 ,Vb到Va 
            if(vst[j]==0&&minn>d[j]){
                minn=d[j];k=j;
            }
            vst[k]=1;//标记 ,加入到Va 
            ans+=d[k];//加上边的权值 
            for(j=1;j<=n;j++)//修改d数组 
            if(vst[j]==0&&d[j]>g[k][j])
            d[j]=g[k][j];
        }
    }
    int main(){
        read();
        prim(1);
        cout<<ans<<endl;
        return 0;
    } 

    Kruskal算法(贪心策略)nlogn

    算法步骤:

    1.将G中的带权边由小到大排序

    2.按照权值由小到大依次选边。诺形成环就放弃这一条,否则标记当前边并计数;

    3.重复2.直到生成树有n-1条边。

    否则遍历完边取不到n-1,就不存在最小生成树。

    ***如何判断环:用并查集:判断新加入的边的两个端点如果在并查集同一集合则成环;

    否则保存当前边,并合并涉及的两个集合。

    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int maxn=100005;
    struct edge{
        int x,y,z;
    }a[maxn];
    int n,m,prt[maxn],ans=0,bj;
    bool cmp(const edge &x,const edge &y){
        return x.z<y.z;
    } 
    int getfather(int x){//找祖先 
        if(prt[x]==x) return x;
        prt[x]=getfather(prt[x]);
        return prt[x];
    }
    void kruskal(){//核心程序 
        int f1,f2,k,i;
        k=0;//记录已经加入的边数 
        for(i=1;i<=n;i++) prt[i]=i;//初始化 
        for(i=1;i<=m;i++){
            f1=getfather(a[i].x);//并查集??不太懂 
            f2=getfather(a[i].y);
            if(f1!=f2){
                ans+=a[i].z;
                prt[f1]=f2;//合并不相同的两个集合 
                k++;
                if(k==n-1) break;
            }
        }
        if(k<n-1){
            cout<<"Impossible"<<endl;bj=0;
            return ;
        }
    }
    int main(){ 
    cin>>n>>m; 
    ans=0;bj=1;
    for(int i=1;i<=m;i++)
    cin>>a[i].x>>a[i].y>>a[i].z;
    sort(a+1,a+m+1,cmp);
    kruskal();
    if(bj) cout<<ans<<endl;
    return 0;
    }
  • 相关阅读:
    MySQL Stack Buffer Overflow Linux x86 32bits
    WordPress Browser Rejector 插件"wppath"远程文件包含漏洞
    JBoss Enterprise Application Platform安全绕过漏洞
    启动NDuiker项目
    java基础>Java常用类库 小强斋
    MyEclipse6.5安装SVN插件的三种方法 小强斋
    jsp>Jsp语法 小强斋
    java基础>Java常用类库 小强斋
    jsp>Jsp语法 小强斋
    java基础>正则表达式 小强斋
  • 原文地址:https://www.cnblogs.com/yfr2zaz/p/10433184.html
Copyright © 2011-2022 走看看