洛谷 P14362 题解

题目:[CSP-S 2025] 道路修复

蓝勾曾葬送在此题上。

让你求最小生成树,我们考虑用kruskal。

但是存在新建村庄的操作。这让我们犯了难。

好消息是 \(k\le 10\),这启发着我们去枚举村庄。

枚举村庄后把与该村庄相连的边加进边集再跑kruscal,时间复杂度 \(\mathcal{O}(2^k(m+nk)\log (m+nk))\),不能通过此题。

这时我们考虑贪心。我们考虑原图最小生成树以外的边不可能作为答案,感性理解这是对的。实际上可以证明,但证明太复杂了,这里略。

于是我们将原图的边数降为了 \(n\) 数量级。时间复杂度 \(\mathcal{O}(2^k(n+nk)\log (n+nk))\),可以得 80pts。

我们可以把排序单独拎出来,在枚举之前排序,枚举时只需要从排好序的边集里取边,然后kruscal。

时间复杂度 \(\mathcal{O}((n+nk)\log (n+nk)+2^k(n+nk))\),可以通过此题。

我们自信地一交。

16pts?

蓝勾没了。

死因:没开long long

AC code:

#include<bits/stdc++.h>
#define int long long//一定要开long long!
using namespace std;
const int M=5e6+7,N=2e4+3,INF=(1ll<<62);
struct Edge{
	int u,v,w,id;
}e[M],d[M],f[M];
bool cmp(Edge x,Edge y){
	return x.w<y.w;
}
int read(){
	int x=0,f=1;
    char c=getchar();
    while(c<'0'||c>'9'){
        if(c=='-')f=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9')
		x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*f;
}
int fa[N];
int n,m,K,ans;
int c[11],a[11][N],b[N],st[11];
int getfa(int x){
	if(x==fa[x]) return x;
	return fa[x]=getfa(fa[x]);
}
void Mergeset(int x,int y){
	fa[x]=getfa(x);
	fa[y]=getfa(y);
	fa[fa[x]]=fa[y];
}
inline void kruscal1(){
	sort(e+1,e+m+1,cmp);
	for(int i=1;i<=n;i++){
		fa[i]=i;
	}
	int tot=0;
	for(int i=1;i<=m;i++){
		int u=e[i].u,v=e[i].v;
		if(getfa(u)!=getfa(v)){
			b[++tot]=i;
			Mergeset(u,v);
			if(tot==n-1) break;
		}
	}
}
inline int kruscal(int res){
	if(res>=ans) return ans;
	for(int i=1;i<=n+K;i++){
		fa[i]=i;
	}
	for(int i=1;i<=m;i++){
		int u=f[i].u,v=f[i].v,w=f[i].w;
		if(getfa(u)!=getfa(v)){
			res+=w;
			if(res>=ans) return ans;
			Mergeset(u,v);
		}
	}
	if(res>=ans) return ans;
	return res;
}
signed main(){
	cin>>n>>m>>K;
	for(int i=1;i<=m;i++)
		e[i].u=read(),e[i].v=read(),e[i].w=read(),e[i].id=0;
	for(int j=1;j<=K;j++){
		c[j]=read();
		for(int i=1;i<=n;i++){
			a[j][i]=read();
		}
	}
	kruscal1();
    m=n-1;
	for(int i=1;i<=n-1;i++)
		d[i].u=e[b[i]].u,d[i].v=e[b[i]].v,d[i].w=e[b[i]].w,d[i].id=0;
	for(int j=1;j<=K;j++){
		for(int k=1;k<=n;k++)
			d[++m].u=n+j,d[m].v=k,d[m].w=a[j][k],d[m].id=j;
	}
	sort(d+1,d+m+1,cmp);
	const int U=(1<<K);
	ans=INF;
	st[0]=1;
	for(int i=0;i<U;i++){
		int res=0;
		m=0;
		for(int j=1;j<=K;j++)
			st[j]=0;
		for(int j=1;j<=K;j++){
			if((1<<j-1)&i){
				res+=c[j];
				st[j]=1;
			}
		}
		for(int j=1;j<=n-1+K*n;j++){
			if(st[d[j].id]){
				f[++m].u=d[j].u,f[m].v=d[j].v,f[m].w=d[j].w,f[m].id=d[j].id;
			}
		}
		ans=kruscal(res);
	}
	cout<<ans<<'\n';
	return 0;
}
posted @ 2025-11-22 11:43  NiYqaq  阅读(28)  评论(0)    收藏  举报