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;
}
题意
平面上有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;
}
相关文章推荐
- uva 1151 Buy or Build
- uva 1151 - Buy or Build poj 2784 Buy or Build(最小生成树)
- UVa 1151 (枚举 + MST) Buy or Build
- uva 1151 Buy or Build (最小生成树)
- UVA 1151 Buy or Build (MST最小生成树,kruscal,变形)
- uva-1151-Buy or Build-二进制枚举子集,并查集,最小生成树,kruskal
- UVA 1151 Buy or Build(最小生成树+枚举子集)
- UVA 1151 Buy or Build MST(最小生成树)
- UVa 1151 Buy or Build
- uva 1151 Buy or Build
- Buy or Build UVA - 1151 MST最小生成树
- UVA 1151 Buy or Build MST
- Uva1151——Buy or Build && POJ2784——Buy or Build
- UVA 1151 Buy or Build (最小生成树)
- UVa 1151 Buy or Build (最小生成树+二进制法暴力求解)
- UVA 1151 Buy or Build
- Buy or Build UVA - 1151
- 【UVA 1151】 Buy or Build (有某些特别的东东的最小生成树)
- uva 1151 - Buy or Build poj 2784 Buy or Build(最小生成树)
- Buy or Build UVA - 1151