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

UVA 1151 Buy or Build

2016-08-10 22:36 295 查看
题目链接  http://acm.hust.edu.cn/vjudge/problem/36013

题意

平面上有n个点(1<=N<=1000),你的任务是让所有n个点连通,

为此,你可以新建一些边,费用等于两个端点的欧几里得距离的平方。

另外还有q(0<=q<=8)个套餐,可以任意购买,即可以不买,也可以买1个 2个 等等 

如果你购买了第i个套餐,该套餐中的所有结点将变得相互连通,第i个套餐的花费为ci。

求最小花费。

就是求最小生成树

对于套餐可以用子集枚举处理, 集合S表示套餐的购买状态

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#include <cmath>
#include <stack>
#include <string>
#include <map>
#include <set>
#define pi acos(-1)
#define LL long long
#define INF 0x3f3f3f3f
using namespace std;
typedef pair<int, int> P;
const int maxn = 1e6 + 5;

struct Pos
{
int x, y;
}pos[1005];
struct Way
{
int u, v, len;
bool operator < (const Way &a) const
{return len < a.len;}
}way[maxn];
int ret[1005], fir = 1;
int cost[10];
vector<int>subnet[10];

int cal(int a, int b)
{
int x = pos[a].x - pos[b].x;
int y = pos[a].y - pos[b].y;
return x*x + y*y;
}
int cmp(Way a, Way b)
{
if (a.len < b.len) return 1;
return 0;
}
int find(int a)
{
if (ret[a] == -1) return a;
return ret[a] = find(ret[a]);
}
int main(void)
{
// freopen("C:\\Users\\wave\\Desktop\\NULL.exe\\NULL\\in.txt","r", stdin);
int T, n, q, i, j, k, t, cnt, sum, ans, t_cnt, S;
cin >> T;
while (T--)
{
if (fir) fir = 0;
else cout << endl;
cin >> n >> q;
for (i = 1; i <= q; i++){
scanf("%d %d", &t, &cost[i]);
subnet[i].clear();
for (j = 1; j <= t; j++){
scanf("%d", &k);
subnet[i].push_back(k);
}
}
for (i = 1; i <= n; i++)
scanf("%d %d", &pos[i].x, &pos[i].y);
cnt = 0;
for (i = 1; i <= n; i++){
for (j = i+1; j <= n; j++){
way[++cnt].u = i;
way[cnt].v = j;
way[cnt].len = cal(i, j);
}
}
sort(way+1, way+1+cnt);
for (i = 1; i <= cnt; i++)
memset(ret, -1, sizeof(ret));
ans = t_cnt = 0;
for (i = 1; i <= cnt; i++){ // 先处理一遍没买套餐的
int x = find(way[i].u);
int y = find(way[i].v);
if (x == y) continue;
ret[x] = y;
ans += way[i].len;
t_cnt++;
if (t_cnt == n-1) break;
}
for (S = 1; S < (1<<q); S++){ // 枚举套餐状态
memset(ret, -1, sizeof(ret));
sum = t_cnt = 0;
for (i = 1; i <= q; i++){
if (!(S & (1<<(i-1)))) continue;
t = subnet[i][0];
sum += cost[i];
for (j = 1; j < subnet[i].size(); j++){
int x = find(subnet[i][j]);
int y = find(t);
if (x != y){
ret[x] = y;
t_cnt++;
}
}
}
for (i = 1; i <= cnt; i++){
if (t_cnt == n-1) break;
int x = find(way[i].u);
int y = find(way[i].v);
if (x == y) continue;
ret[x] = y;
sum += way[i].len;
t_cnt++;
}
ans = min(ans, sum);
}
cout << ans << endl;
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: