10.10 NOTE

UVA1151 买还是建 Buy or Build

题目传送门

平⾯上有 \(n\) 个点,你的任务是让所有 \(n\) 个点连通。为此,你可以新建⼀些边,费⽤等于 \(x,y\) 两个端点的欧⼏⾥得距离。另外还有 \(q\) 个套餐可以购买,如果你购买了第 \(i\) 个套餐,该套餐中的所有节点将变得互相连通。第 \(i\) 个套餐的花费为 \(C_i\)。求最小花费。

\(1<=q<=8\)

思路

先跑一遍最小生成树,由于 \(q\) 很小,那么直接 \(2^q\) 暴力枚举购买了哪些套餐,每次枚举再跑一遍最小生成树即可。

总结

最小生成树

求一个图内使得所有点联通的最简图使得所有边权和最小,显然是一棵树。

Kruskal

简单来说就是贪心。

每次选取边权最小的边连接,如果这条边连接的两个结点已经联通就不选,直到所有的点联通(选取的边数量等于结点数 -1)
用并查集维护两点是否联通。

void Kruskal()
{
	sort(a+1,a+1+m,cmp);
	for(int i=1;i<=m;i++){
		int fx=Find(a[i].x);
		int fy=Find(a[i].y);
		if(fx==fy) continue;
		pre[fx]=fy;
		ans+=a[i].w;
		cnt++;
		if(cnt==n-1)
		break; 
	}
}

Prim

变种,而且还是 \(Dijkstra\) 的变种。

维护两个集合分别代表已经维护的生成树和未被选取的点集。
每次逐步选取与当前生成树相邻的权值最小的边,直到所有的点被选入生成树。

用优先队列(小根堆)维护边即可。

void Prim()
{
		q.push((node) {0, 0});
		while(!q.empty()||cnt < n) // 进行n-1次 
		{
			node x = q.top();
			q.pop();
			if(vis[x.u]) continue;
			vis[x.u] = true;
			cnt++;
			ans += x.w;
			for(int i = head[x.u]; i ; i = a[i].next) 
				if(a[i].w < dis[a[i].to]) {
					dis[a[i].to] = a[i].w;
					q.push((node) {a[i].to, a[i].w});
				}
		}
}

非常简单。

Code

#include<bits/stdc++.h>
#define Iseri namespace
#define Nina std
#define Kawaragi int
#define Momoka main
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define ll long long
#define ull unsigned long long
#define endl "\n"
const int maxn=1005;
const int inf=0x3f3f3f3f;
const int mod=998244353;

using Iseri Nina;

inline ll read(){
    ll x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
    return x*f;
}

//===========================================================

ll T,n,q,f[maxn],x[maxn],y[maxn],w[maxn],def[15][maxn];

struct node{
    ll x,y,z;
    bool operator<(node A)const{
        return z<A.z;
    }
};

vector<node>e;

inline ll find(ll x){
    if(f[x]==x)return x;
    else return f[x]=find(f[x]);
}

Kawaragi Momoka(){
    T=read();
    while(T--){
        e.clear();
        n=read(),q=read();
        for(ll i=1;i<=q;i++){
            def[i][0]=read(),w[i]=read();
            for(ll j=1;j<=def[i][0];j++)def[i][j]=read();
        }
        for(ll i=1;i<=n;i++){
            x[i]=read(),y[i]=read();
            for(ll j=1;j<i;j++) 
                e.push_back({i,j,((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]))});
        }
        sort(e.begin(),e.end());

        ll res=0,ans=0;
        for(ll i=1;i<=n;i++)f[i]=i;
        
        for(ll i=0;i<e.size();i++){
            ll x=e[i].x,y=e[i].y;
            x=find(x),y=find(y);
            if(x!=y){
                f[x]=y;
                ans+=e[i].z;
                res++;
                if(res == n-1) break;
            }
        }

        ll s=(1<<q)-1;
        for(ll i=0;i<=s;i++){
            ll cnt=0;
            for(ll j=1;j<=n;j++)f[j]=j;
            
            for(ll j=1;j<=q;j++){ 
                if(i&(1<<(j-1))){
                    cnt+=w[j];
                    for(ll k=2;k<=def[j][0];k++){
                        ll x=def[j][k],y=def[j][1]; 
                        x=find(x),y=find(y);
                        if(x!=y)f[x]=y;
                    }
                }
            }
            
            for(ll j=0;j<e.size();j++){
                ll x=e[j].x,y=e[j].y;
                x=find(x),y=find(y);
                if(x!=y){
                    f[x]=y;
                    cnt+=e[j].z;
                }
            }

            ans=min(ans,cnt);
        }

        printf("%lld\n",ans);
        if(T) printf("\n");
    }
    return 0;
}
posted @ 2025-11-13 23:54  Amiyawasdonkey  阅读(0)  评论(0)    收藏  举报