您的位置:首页 > 产品设计 > UI/UE

UVA - 1151 Buy or Build(最小生成树+二进制枚举子集)

2017-05-18 15:16 417 查看
点击打开题目链接



题目大意:给出n个点的坐标,连边的费用为两端点的欧几里得距离。给出q种套餐,购买某种套餐花费Ci,该套餐中所有点将连通,求最小花费。

思路:读完题后知道是kruskal最短路问题,但如果枚举所有套餐,又要给所有边排序,又要kruskal,规模太大肯定超时。

所以需要优化:先kruskal求一次得到n-1条边,然后从这n-1条边中用二进制枚举子集的方法枚举套餐。

附上AC代码:

#include<cstdio>
#include<algorithm>

using namespace std;
const int maxn = 1000+5;
typedef long long ll;
int T;//T组样例
int n, q;//共n个点,q个套餐
int city_num[8], pack_spend[8];//city_num[]:单个套餐内的点数目 pack_spend[]:套餐花费
int pack_city[8][maxn];//pack_city[]:单个套餐内点的集合
int x[maxn], y[maxn];//坐标
int par[maxn];//根节点
int m, cnt;

struct edges {
int fr, to, val;
bool operator <(const edges & e)
{
return val < e.val;
}
}_edge[maxn*maxn],edge[maxn];//
//初始化
void init()
{
for (int i = 0; i <= n; i++)par[i] = i;
}
//找根节点
int find(int x)
{
return x == par[x] ? x : par[x] = find(par[x]);
}
//计算欧几里得距离
int dis(int a, int b)
{
return (x[a] - x[b])*(x[a] - x[b]) + (y[a] - y[b])*(y[a] - y[b]);
}
//kruskal
ll kruskal()
{
ll ans = 0;
for (int i = 1; i < n; i++)
{
int dx = find(edge[i].fr);
int dy = find(edge[i].to);
if (dx != dy)
{
par[dx] = dy;
ans += edge[i].val;
}
}
return ans;
}

int main()
{
//ios::sync_with_stdio(false);
scanf("%d",&T);

while(T--)
{
cnt = m = 0;
//read
scanf("%d %d", &n, &q);
for (int i = 0; i < q; i++)
{
scanf("%d%d", & city_num[i], & pack_spend[i]);
for (int j = 1; j <= city_num[i]; j++)
scanf("%d", & pack_city[i][j]);
}

for (int i = 1; i <= n; i++)
scanf("%d%d", &x[i], &y[i]);
//solve
init();
for (int i = 1; i <= n; i++)
{
for (int j = i + 1; j <= n; j++)
{
_edge[++cnt].fr = i;
_edge[cnt].to = j;
_edge[cnt].val = dis(i, j);
}
}
//全体点的kruskal
ll ans = 0;
sort(_edge + 1, _edge + cnt + 1);
for (int i = 1; i <= cnt; i++)
{
int dx = find(_edge[i].fr);
int dy = find(_edge[i].to);
if (dx != dy)
{
par[dx] = dy;
ans += _edge[i].val;
edge[++m] = _edge[i];
}
}
//套餐的二进制枚举
for (int t = 0; t < (1 << q); t++)
{
ll anxd = 0;
init();
for (int i = 0; i < q; i++)
{
if (t&(1 << i))
{
anxd += pack_spend[i];
for (int j = 2; j <= city_num[i]; j++)
par[find(pack_city[i][j-1])] = find(pack_city[i][j]);
}
}
anxd += kruskal();
ans = min(ans, anxd);
}
printf("%lld\n", ans);
if (T)printf("\n");
}
//	system("pause");
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息