zoukankan      html  css  js  c++  java
  • Electrification Plan 最小生成树(prim+krusl+堆优化prim)

    题目

    题意:

      无向图,给n个城市,n*n条边,每条边都有一个权值 代表修路的代价,其中有k个点有发电站,给出这k个点的编号,要每一个城市都连到发电站,问最小的修路代价。

    思路:

      prim:把发电站之间e[i][j]都设置为0,然后模板套进去就行。

      krusl:把所有的发电站都先弄进一个并查集(做法比较机智,先拿其中一个发电站,把剩下的发电站分别与这个发电站找父节点,分别弄进并查集就行)。 然后按权值从小到大 排序,不是同一个并查集的就sum+=,再弄进并查集。

    复杂度O(n*n)

    #include<iostream>
    #include<cstdio>
    #include <cctype>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<string>
    #include<cmath>
    #include<set>
    #include<vector>
    #include<stack>
    #include<queue>
    #include<map>
    using namespace std;
    #define ll long long
    #define mem(a,x) memset(a,x,sizeof(a))
    #define se second
    #define fi first
    const ll mod=998244353;
    const int INF= 0x3f3f3f3f;
    const int N=2e5+5;
    
    int n,m;
    int e[105][105];
    int b[105],dis[105],vis[105];
    
    void prim()
    {
        for(int i=1;i<=n;i++)
        {
            vis[i]=0; 
            dis[i]=e[1][i];
        }
        int u,minn,sum=0;
        vis[1]=1;
        for(int i=1;i<n;i++)
        {
            minn=INF;
            for(int j=1;j<=n;j++)
            {
                if(!vis[j] && minn>dis[j])
                {
                    u=j;
                    minn=dis[j];
                }
            }
            vis[u]=1;
            sum+=minn;
            for(int j=1;j<=n;j++)
            {
                if(!vis[j] && e[u][j]<dis[j])
                    dis[j]=e[u][j];
            }
        }
        printf("%d
    ",sum);
    }
    int main()
    {
        cin>>n>>m;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                if(i==j) e[i][j]=0;
                else e[i][j]=INF;
                
        for(int i=1;i<=m;i++) scanf("%d",&b[i]);
        
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                scanf("%d",&e[i][j]);
            }
        }
        
        for(int i=1;i<=m;i++)
            for(int j=1;j<=m;j++)
                e[b[i]][b[j]]=0;
        
        prim();
    }
    朴素prim做法

    复杂度O(mlogm)

    #include<iostream>
    #include<cstdio>
    #include <cctype>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<string>
    #include<cmath>
    #include<set>
    #include<vector>
    #include<stack>
    #include<queue>
    #include<map>
    using namespace std;
    #define ll long long
    #define mem(a,x) memset(a,x,sizeof(a))
    #define se second
    #define fi first
    const ll mod=998244353;
    const int INF= 0x3f3f3f3f;
    const int N=2e5+5;
    
    int f[N],n,m;
    struct edge
    {
        int u,v,w;
    }e[N];
    
    bool cmp(edge x,edge y)
    {
        return x.w<y.w;
    }
    
    int getf(int x)
    {
        if(x!=f[x])
            f[x]=getf(f[x]);
        return f[x];
    }
    int krusl(int num)
    {
        int fa,fb,sum=0,cnt=0;
        for(int i=1;i<=num;i++)
        {
            fa=getf(e[i].u);
            fb=getf(e[i].v);
            if(fa!=fb)
            {
                f[fa]=fb;
                sum+=e[i].w;
                cnt++;
            }
            if(cnt==n-m) break;
        }
        return sum;
    }
    int main()
    {
        cin>>n>>m;
        for(int i=0;i<=n;i++) f[i]=i;
        
        int q;
        cin>>q; //拿q与其他所有的发电站都连接起来 
        for(int i=2;i<=m;i++)
        {
            int fa,fb,a;
            cin>>a;
            fa=getf(a);
            fb=getf(q);
            if(fa!=fb)
                f[fa]=fb;
        }
        int cnt=0;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                e[++cnt].u=i;
                e[cnt].v=j;
                scanf("%d",&e[cnt].w);
            }
        }
        sort(e+1,e+1+cnt,cmp);
            
        cout<<krusl(cnt)<<endl;
        
    }
    krusl做法

    参考博客

    复杂度O(mlogm)

    #include<iostream>
    #include<cstdio>
    #include <cctype>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<string>
    #include<cmath>
    #include<set>
    #include<vector>
    #include<stack>
    #include<queue>
    #include<map>
    using namespace std;
    #define ll long long
    #define mem(a,x) memset(a,x,sizeof(a))
    #define se second
    #define fi first
    const ll mod=998244353;
    const int INF= 0x3f3f3f3f;
    const int N=2e5+5;
    
    int n,m;
    int vis[N];
    struct edge
    {
        int u,v,w;
        bool operator<(const edge &r)const{ //priority_queue中用 
            return r.w<w;
        }
        edge(int _v,int _w):v(_v),w(_w){}  //vector中用 
    };
    vector<edge> ve[N];
    
    void prim()
    {
        priority_queue<edge> q;
        for(int i=0;i<ve[1].size();i++)
            q.push(ve[1][i]);
        int cnt=n-1,sum=0;
        vis[1]=1;
        while(!q.empty() && cnt)
        {
            edge cur=q.top();
            q.pop();
            while(vis[cur.v])
            {
                cur=q.top();
                q.pop();
            }
            sum+=cur.w;
            vis[cur.v]=1;
            for(int i=0;i<ve[cur.v].size();i++)
            {
                if(!vis[ ve[cur.v][i].v ] )
                    q.push(ve[cur.v][i]);
            }
            cnt--;
        }
        printf("%d
    ",sum);
    }
    int main()
    {
        int u,v,w; 
        cin>>n>>m;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&u,&v,&w);
            ve[u].push_back(edge(v,w)); 
            ve[v].push_back(edge(u,w)); 
        }
        prim();
    }
    prim堆优化

    牛客题目链接

    题意:

      毒气炸弹需要 k 种不同类型元素构成,Applese一共有 n 瓶含有这些元素的试剂。 已知元素混合遵循 m 条规律,每一条规律都可以用 "x y c" 描述。表示将第 x 瓶试剂混入第 y 瓶试剂或者把第 y 瓶试剂混入第 x 瓶试剂,需要消耗 c 的脑力。特别地,除了这 m 条规律外,Applese 可以将任意两瓶相同元素的试剂混合,且不需要消耗脑力。Applese 想要配出毒气炸弹,就需要使 S 中含有  这 k 种元素。它想知道自己最少花费多少脑力可以把毒气炸弹做出来。

    思路:

      和上面题目类似。把所有相同的加入同一个并查集。

    #include<iostream>
    #include<cstdio>
    #include <cctype>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<string>
    #include<cmath>
    #include<set>
    #include<vector>
    #include<stack>
    #include<queue>
    #include<map>
    using namespace std;
    #define ll long long
    #define mem(a,x) memset(a,x,sizeof(a))
    #define se second
    #define fi first
    const ll mod=998244353;
    const int INF= 0x3f3f3f3f;
    const int N=2e5+5;
     
    int f[N],n,m,k;
    struct edge
    {
        int u,v,w;
    }e[N];
     
    struct node
    {
        int pp, vv;
    }a[N];
     
    bool cmp(edge x,edge y)
    {
        return x.w<y.w;
    }
    bool cmp2(node x,node y)
    {
        return x.vv<y.vv;
    }
    int getf(int x)
    {
        if(x!=f[x])
            f[x]=getf(f[x]);
        return f[x];
    }
    ll krusl(int num)
    {
        int fa,fb,cnt=0;
        ll sum=0;
        for(int i=1;i<=num;i++)
        {
            fa=getf(e[i].u);
            fb=getf(e[i].v);
            if(fa!=fb)
            {
                f[fa]=fb;
                sum+=1LL*e[i].w;
                cnt++;
            }
            if(cnt==k-1) break;
        }
        if(cnt!=k-1) return -1;
        else return sum;
    }
    int main()
    {
        cin>>n>>m>>k;
        for(int i=0;i<=n;i++) f[i]=i;
        for(int i=1;i<=n;i++) scanf("%d",&a[i].vv),a[i].pp=i;
        sort(a+1,a+1+n,cmp2);
        int q;
        int fa,fb;
        int j=1;
        for(int i=1;i<=k;i++)
        {
            if(a[j].vv ==i)
            {
                q=a[j].pp;
                j++;
                while(a[j].vv==i)
                {
                    fa=getf(a[j].pp);
                    fb=getf(q);
                    if(fa!=fb)
                        f[fa]=fb;
                    j++;
                }
            }
        }
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
        }
        sort(e+1,e+1+m,cmp);
             
        printf("%lld
    ",krusl(m));
         
    }
    krusl
  • 相关阅读:
    Windows SDK编程(Delphi版) 之 应用基础,楔子
    一个小问题引发的论证思考
    Delphi 组件开发教程指南(7)继续模拟动画显示控件
    用PyInstaller将python转成可执行文件exe笔记
    使用 .Net Memory Profiler 诊断 .NET 应用内存泄漏(方法与实践)
    Microsof Office SharePoint 2007 工作流开发环境搭建
    How to monitor Web server performance by using counter logs in System Monitor in IIS
    LINQ之Order By
    window 性能监视器
    内存泄露检测工具
  • 原文地址:https://www.cnblogs.com/thunder-110/p/10329445.html
Copyright © 2011-2022 走看看