最小生成树的应用 [CSP-S 2025] 道路修复
显而易见, 当 \(k=0\) 时, 我们要求的是最小生成树. kruskal 解决即可.
现在我们要思考的是当 \(k\in[1,10],\ k\in\mathbb{N^*}\) 时的情况.
显然我们可以枚举每一种翻新乡镇的情况, 时间复杂度为 \(O\left(2^k\right)\). 在此基础上跑最小生成树即可. 但是这样时间复杂度变为 \(O\left(2^k(m+nk)\log(m+nk)\right)\).
于是我们不妨先跑一遍 kruskal, 即先得到一个最优答案, 建树. 再在此基础上加边加点, 即将乡镇城市化, 继续跑 kruskal, 时间复杂度预计为 \(O\left((nk)\log (nk)+m\log m+2^k(n+k)\right)\).
初建树
inline void kruskal_inint(){
for(int i=1;i<=n;P(i))f[i]=i;
for(auto [u,v,w]:e){
int u1=find(u),v1=find(v);
if(u1==v1)continue;
f[u1]=v1,new_e.push_back((NODE){u,v,w}),ans+=w;
if((int)new_e.size()==n-1)break;
}
}
signed main(){
for(int i=1,u,v,w;i<=m;P(i)){
std::cin>>u>>v>>w;
e.push_back((NODE){u,v,w});
}
std::sort(e.begin(),e.end());
kruskal_inint();
if(!k){
std::cout<<ans;
exit(0);
}
}
加边加点:
for(int i=1;i<=k;P(i)){
std::cin>>cost[i];
for(int j=1,c;j<=n;P(j)){
std::cin>>c;
new_e.push_back((NODE){j,n+i,c});
}
}
std::sort(new_e.begin(),new_e.end());
枚举加边加点情况:
inline LL kruskal(int state){
LL ans(0),country_cnt(0);
int cnt(0);
for(int i=1;i<=k;P(i)){// 先把 state 给转化成具体的加边加点情况
if((state>>(i-1))&1)build[i]=true,ans+=cost[i],P(country_cnt);
else build[i]=false;
}
for(int i=1;i<=n_all;P(i))f[i]=i;//并查集
for(auto [u,v,w]:new_e){//kruskal
if(v>n&&!build[v-n])continue;
int v1=find(v),u1=find(u);
if(v1==u1)continue;
f[u1]=v1,ans+=w,P(cnt);
if(cnt==n+country_cnt-1)return ans;
}
return 1e18;
}
signed main(){
for(int i=1;i<country_cnt;P(i))
ans=std::min(ans,kruskal(i));
}
全代码:
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<vector>
#define P(A) A=-~A
#define NUMBER1 1000000
#define NUMBER2 10
typedef long long LL;
struct NODE{
int u,v;
LL w;
bool operator<(const NODE &A)const{return w<A.w;}
NODE(int u=0,int v=0,LL w=0):u(u),v(v),w(w){}
};
std::vector<NODE>e,new_e;
int n,m,k,f[NUMBER1+NUMBER2+5],n_all;
LL cost[NUMBER2+5],ans(0);
bool build[NUMBER2+5];
inline int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
inline void kruskal_inint(){
for(int i=1;i<=n;P(i))f[i]=i;
for(auto [u,v,w]:e){
int u1=find(u),v1=find(v);
if(u1==v1)continue;
f[u1]=v1,new_e.push_back((NODE){u,v,w}),ans+=w;
if((int)new_e.size()==n-1)break;
}
}
inline LL kruskal(int state){
LL ans(0),country_cnt(0);
int cnt(0);
for(int i=1;i<=k;P(i)){
if((state>>(i-1))&1)build[i]=true,ans+=cost[i],P(country_cnt);
else build[i]=false;
}
for(int i=1;i<=n_all;P(i))f[i]=i;
for(auto [u,v,w]:new_e){
if(v>n&&!build[v-n])continue;
int v1=find(v),u1=find(u);
if(v1==u1)continue;
f[u1]=v1,ans+=w,P(cnt);
if(cnt==n+country_cnt-1)return ans;
}
return 1e18;
}
signed main(){
std::cin.tie(nullptr)->std::ios::sync_with_stdio(false);
std::cout.tie(nullptr);
std::cin>>n>>m>>k;
n_all=n+k;
int country_cnt=1<<k;
for(int i=1,u,v,w;i<=m;P(i)){
std::cin>>u>>v>>w;
e.push_back((NODE){u,v,w});
}
std::sort(e.begin(),e.end());
kruskal_inint();
if(!k){
std::cout<<ans;
exit(0);
}
for(int i=1;i<=k;P(i)){
std::cin>>cost[i];
for(int j=1,c;j<=n;P(j)){
std::cin>>c;
new_e.push_back((NODE){j,n+i,c});
}
}
std::sort(new_e.begin(),new_e.end());
for(int i=1;i<country_cnt;P(i))
ans=std::min(ans,kruskal(i));
std::cout<<ans;
return 0;
}

浙公网安备 33010602011771号