题意:

  要使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. SQL Server 之 事务隔离级别

    SET TRANSACTION ISOLATION LEVEL xxx  -- 每次设置只针对当前事务块 xxx 取值: READ UNCOMMITTED READ COMMITTED REPEATA ...

  2. C# Socket服务器端如何判断客户端断开

    使用Socket类中的Poll方法,就可以. Socket client //假如已经创建好了,连接到服务器端得Socket的客户端对象. 我们只要client.Poll(10,SelectMode. ...

  3. hdu 4888

    网络流建模,建模不难,难在找环: #include<cstdio> #include<algorithm> #include<vector> #include< ...

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

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

  5. Python分析NGINX LOG版本二

    不好意思,上一版逻辑有错误,(只分析了一次就没了) 此版改正. 按同事要改,作成传参数形式,搞定. #!/usr/bin/env python # coding: utf-8 ############ ...

  6. js 后台异步执行

    public void AlertMsg(string msg, bool async) { string script = string.Format("alert('{0}'); &qu ...

  7. aircrack-ng 字典破解WPA / WPA2

    1. 安装 首先安装两个扩展sudo apt-get install build-essentialsudo apt-get install libssl-dev 然后到http://download ...

  8. lintcode:搜索二维矩阵II

    题目 搜索二维矩阵 II 写出一个高效的算法来搜索m×n矩阵中的值,返回这个值出现的次数. 这个矩阵具有以下特性: 每行中的整数从左到右是排序的. 每一列的整数从上到下是排序的. 在每一行或每一列中没 ...

  9. 编写自己的TRACE函数

    TRACE函数是MFC里面的一个宏,是对OutputDebugString的封装. OutputDebugString的作用是输出调试信息,不要以为这个函数只有在Debug版本才会打日志,即使是Rel ...

  10. python mysql 简单总结(MySQLdb模块 需另外下载)

    python 通过DB-API规范了它所支持的不同的数据库,使得不同的数据库可以使用统一的接口来访问和操作. 满足DB-API规范的的模块必须提供以下属性: 属性名 描述 apilevel DB-AP ...