题意:

  在平面上有n个点,要让所有n个点都连通,所以你要构造一些边来连通他们,连通的费用等于两个端点的欧几里得距离的平方。另外还有q个套餐,可以购买,如果你购买了第i个套餐,该套餐中的所有结点将变得相互连通,第i个套餐的花费为ci。求最小花费。

思路:

  在这里我们可以采取枚举所有可能 + K算法来得出答案,比如这里有三个套餐,我们利用二进制枚举 001、010、011 、100、 101、 110、 111 分别代表第一个和第二个不要,要第三个(001);不要第一个和第三个,要第二个(010).......即 0 代表不要, 1 代表要,然后把要的套餐中的所有点都连通,再用K算法求剩下的未连接的点的最小生成树。

注意:

  在套餐中合并点时不能单纯地让pre[i] = pre[1](i > 1);pre[i]数组代表 pre[i] 和 i 在一个集合里面(并查集);举个栗子:

  有一个套餐是:

  4 10  2 3 4 5

  含义是购买这个套餐中可以让四个点连通,分别是2,3,4,5号点,费用为 10;如果让 pre[3] = pre[4]=pre[5] = 2;

  那么假设还有个套餐:

  3 9 1 5 3

  含义如上 ,如果再写pre[5] = pre[3] = 1;那么假设我购买了这俩个套餐,本应该2 3 4 5 1都在一个集合里面的,但是按照上面那么写 则 2 4 是一个集合, 1 3 5 是一个集合。不符合我的意思,所以购买套餐合并里面的点时应该写成pre[i] = Find(pre[1]);前提是这俩个不在一个集合里面。

代码:

 #include <bits/stdc++.h>
#define prln(x) cout<<(x)<<endl
using namespace std;
typedef long long LL; const double PI = acos(-1);
const double ESP = 1e-8;
const int MAXN = 1000 + 3;
const int MOD = 1e9 + 7;
int pre[MAXN]; typedef struct Point{ //题目中给的点
int x;
int y;
}Po; typedef struct Buy{ //套餐
int m; //购买该套餐可以合并点的个数
int ci; //购买该套餐的费用
int a[MAXN]; //这个套餐可以合并的点的编号
int flag; //是否要购买这个套餐,对每个套餐的这个值进行二进制枚举
}Bu; typedef struct City{ //用来存储图
int u;
int v;
int w;
}Ci; Ci edge[MAXN * MAXN / 2 + 3];
Po pt[MAXN];
Bu buy[11]; int Find(int x) //并查集
{
return x == pre[x] ? x : pre[x] = Find(pre[x]);
} void Stpre(int n)
{
for(int i = 0; i <= n; i++)
pre[i] = i;
} void Ststu()
{
memset(&pt,0,sizeof(Po));
memset(&buy,0,sizeof(Bu));
memset(&edge,0,sizeof(Ci));
} int Ojld(Point a, Point b)
{
int xx = a.x - b.x;
int yy = a.y - b.y;
return xx * xx + yy *yy;
} int mycmp(City a, City b)
{
return a.w < b.w;
} int ksu(int l)//K算法
{
int ans= 0;
for(int i = 1; i<= l; i++)
{
int fv = Find(edge[i].v);
int fu = Find(edge[i].u);
if(fu != fv)
{
pre[fu] = pre[fv];
ans += edge[i].w;
}
}
return ans;
} int main()
{
//freopen("input.txt","r",stdin);
int t;
cin >> t;
while(t--)
{
Ststu();
int n, q;
scanf("%d%d",&n, &q);
for(int i = 1; i <= q; i++)
{
scanf("%d",&buy[i].m);
scanf("%d",&buy[i].ci);
for(int j = 1; j <= buy[i].m; j++)
scanf("%d",&buy[i].a[j]);
}
for(int i = 1; i <= n; i++)
scanf("%d%d",&pt[i].x, &pt[i].y);
int sum = 0;
for(int i = 1; i < n; i++)
{
for(int j = i + 1; j <= n; j++)
{
sum++;
edge[sum].u = i;
edge[sum].v = j;
edge[sum].w = Ojld(pt[i], pt[j]);
//printf("%d %d %d %d\n",sum,i,j,edge[sum].w);
}
}
sort(edge + 1, edge + sum + 1 , mycmp); int ans = 0x7F7F7F7F;
for(int i = 0; i < (1 << q); i++) //二进制枚举
{
Stpre(n);
int temp = i;
int mst = 0;
for(int j = 1; j <= q; j++)
{
if(temp & 1)
{
mst += buy[j].ci;
for(int k = 2; k <= buy[j].m; k++)
{
int fx = Find ( buy[j].a[1] );
int fy = Find( buy[j].a[k] );
if(fy != fx)
pre[fy] = pre[fx];
}
}
temp >>= 1;
}
mst += ksu(sum);
ans = min(ans, mst);
}
printf("%d\n",ans);
if(t)prln("");
}
return 0;
}
												

UVA 1151 Buy or Build MST(最小生成树)的更多相关文章

  1. UVa 1151 - Buy or Build(最小生成树)

    链接: https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem& ...

  2. UVA 1151 Buy or Build (最小生成树)

    先求出原图的最小生成树,然后枚举买哪些套餐,把一个套餐内的点相互之间边权为0,直接用并查集缩点.正确性是基于一个贪心, 在做Kruskal算法是,对于没有进入最小生成树的边,排序在它前面的边不会减少. ...

  3. UVa 1151 Buy or Build【最小生成树】

    题意:给出n个点的坐标,现在需要让这n个点连通,可以直接在点与点之间连边,花费为两点之间欧几里得距离的平方,也可以选购套餐,套餐中所含的点是相互连通的 问最少的花费 首先想kruskal算法中,被加入 ...

  4. UVa 1151 Buy or Build (最小生成树+二进制法暴力求解)

    题意:给定n个点,你的任务是让它们都连通.你可以新建一些边,费用等于两点距离的平方(当然越小越好),另外还有几种“套餐”,可以购买,你购买的话,那么有些边就可以连接起来, 每个“套餐”,也是要花费的, ...

  5. UVA 1151 Buy or Build (MST最小生成树,kruscal,变形)

    题意: 要使n个点之间能够互通,要使两点直接互通需要耗费它们之间的欧几里得距离的平方大小的花费,这说明每两个点都可以使其互通.接着有q个套餐可以选,一旦选了这些套餐,他们所包含的点自动就连起来了,所需 ...

  6. uva 1151 - Buy or Build poj 2784 Buy or Build(最小生成树)

    最小生成树算法简单 只是增加了一些新的东西,对于需要最小生成树算法 和中 并检查使用的一系列 还有一些更深入的了解. 方法的一些复杂问题 #include<cstdio> #include ...

  7. UVA - 1151 Buy or Build (买还是建)(并查集+二进制枚举子集)

    题意:平面上有n个点(1<=n<=1000),你的任务是让所有n个点连通.可以新建边,费用等于两端点欧几里德距离的平方.也可以购买套餐(套餐中的点全部连通).问最小费用. 分析: 1.先将 ...

  8. 紫书 例题 11-3 UVa 1151 (有边集的最小生成树+二进制枚举子集)

    标题指的边集是说这道题的套餐, 是由几条边构成的. 思路是先做一遍最小生成树排除边, 因为如果第一次做没有加入的边, 到后来新加入了很多权值为0的边,这些边肯定排在最前面,然后这条边的前面的那些边肯定 ...

  9. UVA 1151 买还是建(最小生成树)

    买还是建 紫书P358 [题目链接]买还是建 [题目类型]最小生成树 &题解: 这题真的心累,看了3天,最后照着码还是wa,先放lrj代码,以后再看吧 &代码: // UVa1151 ...

随机推荐

  1. react事件处理及动态样式添加

    多数据的事件绑定,循环数据来进行绑定.如下方式就是循环绑定事件的基本代码: this.state.lists.map(function(value,index,array){//代码片段}.bind( ...

  2. 源码分析(一) HashMap 源码分析|JDK8

    HashMap是一个普遍应用于各大JAVA平台的最最最常用的数据结构.<K,V>的存储形式使HashMap备受广大java程序员的喜欢.JDK8中HashMap发生了很大的变化,例如:之前 ...

  3. neutron floating ip 限速

    查看浮动ip的id [root@10e131e69e14 oz]# openstack floating ip show 36.111.0.197 +---------------------+--- ...

  4. 【志银】nginx_php_mysql_phpMyAdmin配置(Windows)

    ✄更新中... 更新日期:2018.11.22 ★版本说明+快捷下载(官网)  nginx  nginx-1.14.1  http://nginx.org/download/nginx-1.14.1. ...

  5. 洛谷P2678跳石头(提高)

    题目背景 一年一度的“跳石头”比赛又要开始了! 题目描述 这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石.组委会已经选择好了两块岩石作为比赛起点和终点. 在起点和终点之间,有 N 块岩石( ...

  6. Go的HttpClient实现

    Go作为相对java更新的语言,本身的http模块就有客户端请求的实现,继上一章Java的实现,这里记录Go的实现,接下来还有python的实现 注(go版本1.6) package main imp ...

  7. 集训队日常训练20181124 DIV2

    急急忙忙要出去比赛就拉了一场有点sb的题目 5202: 网络寻路  时间限制(普通/Java):1000MS/3000MS     内存限制:65536KByte总提交: 15            ...

  8. java 中基本类型与字符串之间的互相转换

    1. 由 基本数据型态转换成 String String 类别中已经提供了将基本数据型态转换成 String 的 static 方法 也就是 String.valueOf() 这个参数多载的方法 有下 ...

  9. Bsd内核选项总结

    Bsd内核选项总结 一: 下面这个选项在每个内核中都要有: machine i386 它指明了机器的硬件体系结构.它必须是i386, pc98, sparc64, alpha, ia64, amd64 ...

  10. CSS Sprite、CSS雪碧图应用实例

    CSS Sprites技术被国内一些人称为CSS雪碧图,其实就是把网页中一些背景图片整合到一张图片文件中,再利用CSS的“background-image”,“background- repeat”, ...