1 条题解
-
0

// 最小生成树+状态枚举 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
信息
- ID
- 1375
- 时间
- 1000ms
- 内存
- 512MiB
- 难度
- 5
- 标签
- 递交数
- 73
- 已通过
- 30
- 上传者