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;
}

浙公网安备 33010602011771号