CSP-S 2025 T2 [道路建设]解题报告

前言

赛时只拿到了$ kruskal$板子的 \(A\)性质的 \(32pts\),真正唐完,,,,

切入

首先我们可以一眼顶针看出这是一道最小生成树的题,然后发现\(K\leq10\),可以想到直接暴力枚举\(2^k\)次的不同排列,然后跑一遍\(kruskal\),但是每一次枚举都需要暴力地建一次图,发现重复贡献太多,故考虑优化

优化

先对给出的原边和村庄的边建图,然后根据枚举的条件去封锁没有城市化改造的村庄的边,时间复杂度应该是\(O(2^km+2^kkn)\),其实这道题虽说是蓝但也还挺好想的,对于我的难点来说是不会代码上的实现,导致场上浪费了大量的时间还是打不出来,码力还是太弱了啊......

AC Code
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
#define endll " "
#define fre(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout);
#define pii pair<int,int>
#define pb push_back
#define eb emplace_back
#define it inline int
#define iv inline void
#define ib inline bool
#define sakura_no_uta return 0
using namespace std;
const int MAXN=10000050;
const int INF=0x3f3f3f3f3f3f3f3f;
const int MOD=998244353;
it gcd(int x,int y) {return y==0?x:gcd(y,x%y);}
it lcm(int x,int y) {return y/gcd(x,y)*x;}
it max(int x,int y) {return x>y?x:y;}
it min(int x,int y) {return x<y?x:y;}
it ksm(int x,int m,int mod)
{
	int res=1,bas=x%mod;
	while(m)
	{
		if(m&1)
			res=(res*bas)%mod;
		bas=(bas*bas)%mod;
		m >>= 1;
	}
	return res;
}
int n,m,l,r,u,v,w,cnt,tot,ans=INF,cnt1,cnt2,cnt3,lim,T,head[MAXN],k,a[11][MAXN],c[MAXN],fa[MAXN],val;
bool vis[11];
it find(int x)
{
	if(x==fa[x])
		return x;
	return fa[x]=find(fa[x]);
}
struct edge
{
	int fr,to,w;
}e[MAXN];
ib cmp(edge x,edge y)
{
	return x.w<y.w;
}
iv add_edge(int u,int v,int w)
{
	e[++tot].fr=u;
	e[tot].to=v;
	e[tot].w=w;
}
it calc(int cnt,int tot)
{
	int sum=cnt1=0;
	for(int i=1;i<=tot;i++)
	{
		if((e[i].fr>n&&!vis[e[i].fr-n]) || (e[i].to>n&&!vis[e[i].to-n]))
			continue;
		int uu=find(e[i].fr),vv=find(e[i].to);
		if(uu!=vv)
		{
			fa[uu]=vv;
			sum+=e[i].w;
			cnt1++;
			if(cnt1==n-1+cnt)
				break;
		}
	}
	return sum;
}
iv solve()
{
	lim=1<<k;
	for(int i=0;i<lim;i++)
	{
		memset(vis,0,sizeof(vis));
		cnt=val=0;
		for(int j=1;j<=k;j++)
		{
			if((1<<(j-1))&i)
			{
				val+=c[j];
				vis[j]=1;
				++cnt;
			}
		}
		for(int i=1;i<=n+k;i++)
			fa[i]=i;
		ans=min(ans,val+calc(cnt,tot));
	}
}
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin >> n >> m >> k;
	for(int i=1;i<=m;i++)
	{
		cin >> u >> v >> w;
		add_edge(u,v,w);
	}
	for(int i=1;i<=k;i++)
	{
		cin >> c[i];
		for(int j=1;j<=n;j++)
		{
			cin >> a[i][j];
			add_edge(n+i,j,a[i][j]);
		}
	}
	sort(e+1,e+tot+1,cmp);
	solve();
	cout<<ans;
	sakura_no_uta;
}
posted @ 2025-11-06 19:32  KLaneX  阅读(13)  评论(0)    收藏  举报