2 条题解

  • 0
    @ 2026-1-22 11:24:25

    Prim算法:

    #include <bits/stdc++.h>
    using namespace std;
    struct node{int u,v,w;};
    // Prim:适合稠密图,这里用邻接矩阵实现,方便 n<=100
    int n,m;
    vector<vector<int>> g;
    //dis:表示从当前已加入生成树的点,到点 i 的最小连接边的权值
    vector<int> vis,dis,pre;
    const int INF=1e9;
    int main(){
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        cin>>n>>m;
        g.assign(n+1,vector<int>(n+1,INF));
        for(int i=1;i<=n;i++) g[i][i]=0;
        for(int i=0;i<m;i++){
            int u,v,w;
            cin>>u>>v>>w;
            if(u>v) swap(u,v);
            // 可能有重边,保留最小造价
            if(w<g[u][v]){
                g[u][v]=g[v][u]=w;
            }
        }
        vis.assign(n+1,0);
        dis.assign(n+1,INF);
        pre.assign(n+1,0);
        int st=1; // 从 1 号点开始扩展
        dis[st]=0;
        pre[st]=0;
        for(int it=1;it<=n;it++){
            int x=0,best=INF;
            // 选一个未加入生成树且 dis 最小的点 x
            for(int i=1;i<=n;i++){
                if(!vis[i] && dis[i]<best){
                    best=dis[i];
                    x=i;
                }
            }
            if(x==0) break; // 理论上不会发生(题目保证连通)
            vis[x]=1; // 把 x 加入生成树集合
            // 用 x 去更新其它点到生成树的最小连接边
            for(int y=1;y<=n;y++){
                if(!vis[y] && g[x][y]<dis[y]){
                    dis[y]=g[x][y];
                    pre[y]=x; // 记录 y 的前驱(即 MST 中连接 y 的那条边来自 x)
                }
            }
        }
        // 收集 MST 的 n-1 条边:每个点(除起点)都会有一个 pre
        vector<node> ans;
        ans.reserve(n-1);
        for(int v=1;v<=n;v++){
            if(v==st) continue;
            int u=pre[v];
            int a=u,b=v;
            if(a>b) swap(a,b);
            ans.push_back({a,b,0});
        }
        // 按(u,v)排序输出,匹配题目常见格式
        sort(ans.begin(),ans.end(),[](const node& x,const node& y){
            if(x.u==y.u) return x.v<y.v;
            return x.u<y.u;
        });
        for(auto &e:ans) cout<<e.u<<" "<<e.v<<"\n";
        return 0;
    }
    
    
    • 0
      @ 2026-1-22 10:37:46

      Kruskal

      #include <bits/stdc++.h>
      using namespace std;
      struct node{int u,v,w;};
      int n,m,cnt=0;
      vector<node> b,a;
      vector<int> pa,sz;
      // 初始化并查集:每个点自成一个集合
      void init(int n){
          pa.resize(n+1);
          sz.assign(n+1,1);
          for(int i=1;i<=n;i++) pa[i]=i;
      }
      // 查找根节点(带路径压缩)
      int findr(int x){
          if(pa[x]!=x) pa[x]=findr(pa[x]);
          return pa[x];
      }
      // 合并两个集合(按大小合并)
      void join(int x,int y){
          int rx=findr(x),ry=findr(y);
          if(rx==ry) return;
          if(sz[rx]<sz[ry]) swap(rx,ry);
          pa[ry]=rx;
          sz[rx]+=sz[ry];
      }
      // Kruskal:按边权从小到大选边,避免成环
      void kruskal(){
          a.clear();
          a.reserve(n-1);
          cnt=0;
          for(int i=0;i<m;i++){
              int u=b[i].u,v=b[i].v;
              if(findr(u)!=findr(v)){
                  join(u,v);
                  a.push_back({u,v,b[i].w}); // 记录选中的边
                  cnt++;
                  if(cnt==n-1) break; // 生成树边数够了就结束
              }
          }
      }
      bool cmpw(const node& x,const node& y){return x.w<y.w;}
      bool cmpuv(const node& x,const node& y){
          if(x.u==y.u) return x.v<y.v;
          return x.u<y.u;
      }
      int main(){
          ios::sync_with_stdio(false);
          cin.tie(nullptr);
          cin>>n>>m;
          b.resize(m);
          for(int i=0;i<m;i++){
              cin>>b[i].u>>b[i].v>>b[i].w;
              if(b[i].u>b[i].v) swap(b[i].u,b[i].v); // 统一保证 u<=v,便于最终排序输出
          }
          init(n);
          sort(b.begin(),b.end(),cmpw); // 按权值排序
          kruskal(); // 跑 Kruskal 得到 MST
          sort(a.begin(),a.end(),cmpuv); // 按(u,v)排序,匹配题目输出习惯
          for(auto &e:a) cout<<e.u<<" "<<e.v<<"\n";
          return 0;
      }
      
      • 1

      信息

      ID
      826
      时间
      1000ms
      内存
      256MiB
      难度
      10
      标签
      递交数
      12
      已通过
      2
      上传者