题意:

  要使n个点之间能够互通,要使两点直接互通需要耗费它们之间的欧几里得距离的平方大小的花费,这说明每两个点都可以使其互通。接着有q个套餐可以选,一旦选了这些套餐,他们所包含的点自动就连起来了,所需要做的就是连上还未通的即可,q<=8。可以多买。求最小生成树所需的代价。

思路:

  与普通求MST不同的就是多了套餐,而且还可以多买。每个套餐有买或不买两种可能,那么有28种可能,即256种。

  如果不买套餐,至少需要求1次MST是确定的,这个复杂度已经是O(n*n)了。还得考虑哪些餐套可以搭配来买更便宜,那么就穷举这256种组合,每种组合来一次MST,但是不再需要O(n*n)了,只需要用第一次生成树时所挑出来的边即可。

  具体做法是,将套餐内的所有点先连接(并查集),再用MST的边来一次kruscal(记得加上套餐费)。对于每个组合都这样做,就能求出结果了。

  特别要注意:每两个输出结果之间要1个空行,末尾不需要再空行,否则出错。

 #include <bits/stdc++.h>
#define LL long long
using namespace std;
const int N=+;
const int INF=0x7f7f7f7f;
vector<int> vect[];
vector< pair<int,int> > cor, e, tree;
int t, r, n, q, a, b;
int cost[], pre[N], g[N][N];; int cmp(pair<int,int> a,pair<int,int> b){return g[a.first][a.second]<g[b.first][b.second]? true: false;}//按照距离来排序
int dis( pair<int,int> a,pair<int,int> b ){return (a.first-b.first)*(a.first-b.first) +(a.second-b.second)*(a.second-b.second) ;}//不需要开方 int find(int x){return pre[x]==x? x: pre[x]=find(pre[x]);} //查
void joint(int a,int b){a=find(a),b=find(b);if(a!=b) pre[a]=b;} //并 LL kruscal() //将生成树的树边取出
{
for(int i=; i<=n; i++) pre[i]=i;
int cnt=;
LL sum=;
for(int i=; i<e.size(); i++)
{
int a=e[i].first;
int b=e[i].second;
if(find(a)!=find(b))
{
cnt++;
tree.push_back(e[i]); //收藏边
sum+=g[a][b]; //统计权值
joint(a,b); //a和b是点
if(cnt>=n-) return sum;
}
}
return sum;
} LL kruscal_2() //带套餐的
{
LL sum=;
for(int i=; i<tree.size(); i++)
{
int a=tree[i].first;
int b=tree[i].second;
if(find(a)!=find(b))
{
sum+=g[a][b];
joint(a,b);
}
}
return sum;
} LL cal()
{
sort(e.begin(), e.end(), cmp);
tree.clear();
LL ans=kruscal(); //第一次生成树,挑出有用边
int choice=;
while(q--) choice+=choice;
for(int i=; i<choice; i++)
{
for(int j=; j<=n; j++) pre[j]=j;
int tmp=i, cnt=;
LL sum=;
while(tmp) //先将欲买套餐的pre归类
{
if((tmp&)==) //第cnt个套餐要了
{
sum+=cost[cnt];
for(int j=; j<vect[cnt].size(); j++) joint(vect[cnt][j-],vect[cnt][j]);
}
tmp>>=;
cnt++;
}
ans=min(ans, sum+kruscal_2()); //再生成树
}
return ans;
} int main()
{
freopen("input.txt", "r", stdin);
cin>>t;
while(t--)
{
cin>>n>>q;
for(int i=; i<=q; i++) //每个套餐
{
scanf("%d%d",&a,&cost[i]);
vect[i].clear();
while(a--)
{
scanf("%d",&r);
vect[i].push_back(r);
}
}
cor.clear();
for(int i=; i<n; i++)
{
scanf("%d%d",&a,&b);
cor.push_back(make_pair(a,b)); //每个点的坐标
} memset(g, , sizeof(g));
e.clear();
for(int i=; i<=n; i++) //计算出距离
{
for(int j=i+; j<=n; j++)
{
g[i][j]=g[j][i]= dis(cor[i-],cor[j-]);
e.push_back(make_pair(i,j));
}
}
cout<<cal()<<endl;
if(t) printf("\n");
}
return ;
}

AC代码

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

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

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

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

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

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

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

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

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

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

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

  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. struts.properties配置详解(转)

    Struts 2框架有两个核心配置文件,其中struts.xml文件主要负责管理应用中的Action映射,以及该Action包含的Result定义等.除此之 外,Struts 2框架还包含     s ...

  2. 《head first java 》读书笔记(二)

    Updated 2014/03/27 P402-P454 Updated 2014/04/03 P454- 世界三大首席管理器: border, flow, box borderLayout: 五个区 ...

  3. IMP不到指定的表空间

    ==============================================================================只导dmp文件中的几个表数据,解决导入时ta ...

  4. 安装numpy/scipy/scikit-learn的方法

    安装numpy 和 scipy sudo yum install lapack lapack-devel blas blas-devel   sudo yum install numpy.x86_64 ...

  5. 【设计模式六大原则5】迪米特法则(Law Of Demeter)

      定义:一个对象应该对其他对象保持最少的了解. 问题由来:类与类之间的关系越密切,耦合度越大,当一个类发生改变时,对另一个类的影响也越大. 解决方案:尽量降低类与类之间的耦合. 自从我们接触编程开始 ...

  6. ZOJ 1642 Match for Bonus (DP)

    题目链接 题意 : 给你两个字符串,两个字符串都有共同的字母,给你每个字母的值,规则是,找出两个字符串中的共同的一个字母,然后这个字母的值就可以加到自己的分数上,但是这步操作之后,这两个字母及其之前的 ...

  7. hdu2013

    http://acm.hdu.edu.cn/showproblem.php?pid=2013 #include<iostream> #include<stdio.h> #inc ...

  8. linux内核--进程与线程

    http://blog.csdn.net/yusiguyuan/article/details/12154823 在<linux内核设计与实现>中第三章讲解了进程管理,在关于进程和线程的概 ...

  9. ExecutorService中submit和execute的区别

    在Java5之后,并发线程这块发生了根本的变化,最重要的莫过于新的启动.调度.管理线程的一大堆API了.在Java5以后,通过Executor来启动线程比用Thread的start()更好.在新特征中 ...

  10. MVVM 代码记录

      一.XML <Page x:Class="MVVM.MainPage" xmlns="http://schemas.microsoft.com/winfx/20 ...