1 条题解

  • 0
    @ 2026-6-14 14:48:07

    // 最小生成树+状态枚举 O(mlogm+knlogkn+2^k*kn)
    #include<bits/stdc++.h>
    using namespace std;
    
    int read(){
      int f=1,x=0; char c=getchar();
      for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
      for(;isdigit(c);c=getchar()) x=10*x+c-'0';
      return f*x;
    }
    const int N=10005,M=1000005;
    struct E{int u,v,w;}e[M]; //边集
    int fa[N],c[12],vis[12];
    
    int find(int u){
      return fa[u]==u?u:fa[u]=find(fa[u]);
    }
    int main(){
      int n=read(),m=read(),k=read();
      for(int i=1;i<=m;i++)e[i]={read(),read(),read()};
      
      sort(e+1,e+1+m,[&](E a,E b){return a.w<b.w;});
      for(int i=1;i<=n;i++) fa[i]=i;
      int tot=0;
      for(int i=1;i<=m;i++){
        int u=find(e[i].u),v=find(e[i].v);
        if(u!=v){
          fa[v]=u;
          e[++tot]=e[i];
          if(tot==n-1) break;
        }
      } //Kruskal
      
      for(int i=1;i<=k;i++){
        c[i]=read();
        for(int j=1;j<=n;j++)e[++tot]={n+i,j,read()};
      } //连城市到乡镇的边
      
      sort(e+1,e+1+tot,[&](E a,E b){return a.w<b.w;});
      long long ans=1e18;
      for(int st=0;st<(1<<k);st++){ //枚举k个点的选择状态
        long long sum=0; int num=0;
        for(int i=1;i<=k;i++){ //1011:选第1,2,4乡镇
          if((st>>(i-1))&1){
            ++num; //选择乡镇的个数
            vis[i]=1; //选择乡镇i
            sum+=c[i]; //加上点权
          }
          else vis[i]=0;
        }
        
        for(int i=1;i<=n+k;i++) fa[i]=i;
        int cnt=0;
        for(int i=1;i<=tot;i++){ //tot=n-1+kn
          int u=e[i].u,v=e[i].v;
          if(u>n && !vis[u-n]) continue; //乡镇u没选
          u=find(u),v=find(v);
          if(u!=v){
            fa[v]=u;
            sum+=e[i].w; //累加边权
            if(++cnt==n+num-1) break;
          }
        }
        ans=min(ans,sum); //各种方案中的最小值
      }
      cout<<ans;
    }
    
    • 1

    D145 最小生成树 Kruskal 算法[CSP-S 2025] 道路修复

    信息

    ID
    1375
    时间
    1000ms
    内存
    512MiB
    难度
    5
    标签
    递交数
    73
    已通过
    30
    上传者