UVA 1151 Buy or build(并查集之六)

题意:n个结点,以及m个组合,可以任意选择。求最小花费。

因为组合最多只有8个,可以枚举。

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<string.h>
#define MAX 1007
#define INTMAX (int)1e9
using namespace std;
struct list_buy
{
    int num;
    int price;
    int node[MAX];
};
struct list_buy l[10];
struct point
{
    int x;
    int y;
};
struct point p[MAX];
struct Line
{
    int u;
    int v;
    int w;
};
struct Line line[MAX*MAX];
int n,m,x[10],flag[MAX],count_line,min_ans;
int pre[MAX];
int cmp(struct Line a,struct Line b)
{
    return a.w<b.w;
}
int cal(struct point a,struct point b)
{
    return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
}
void init()
{
    for(int i=0;i<n;i++)
    {
        pre[i]=i;
        flag[i]=0;
    }
}
int find(int x)
{
    int r=x;
    while(r!=pre[r])
        r=pre[r];
    int i=x,j;
    while(i!=r)
    {
        j=pre[i];
        pre[i]=r;
        i=j;
    }
    return r;
}
void join(int x,int y)
{
    int fx=find(x);
    int fy=find(y);
    if(fx!=fy)
        pre[fx]=fy;
}
int kruskal()
{
    int ans=0;
    sort(line,line+count_line,cmp);
    for(int i=0;i<count_line;i++)
    {
        int fx=find(line[i].u);
        int fy=find(line[i].v);
        if(fx!=fy)
        {
            ans+=line[i].w;
            pre[fx]=fy;
            for(int j=0;j<n;j++)
                pre[j]=find(j);
            int temp=0;
            for(int j=0;j<n-1;j++)
            {
                if(pre[j]!=pre[j+1])
                {
                    temp=1;
                    break;
                }
            }
            if(temp==0)
                return ans;
        }
    }
    return ans;
}
int solve()
{
    int ans=0;
    init();
    for(int i=0;i<m;i++)
    {
        if(x[i])
        {
            ans+=l[i].price;
            for(int j=0;j<l[i].num-1;j++)
            {
                int fx=find(l[i].node[j]);
                int fy=find(l[i].node[j+1]);
                pre[fx]=fy;
            }
        }
    }
    int temp=0;
    for(int i=0;i<n-1;i++)
    {
        if(pre[i]!=pre[i+1])
        {
            temp=1;
            break;
        }
    }
    if(temp==0)
        return ans;
    else
    {
        temp=kruskal();
        if(temp!=-1)
            ans+=temp;
        else
            return -1;
    }
    return ans;
}
void fun(int t)
{
    if(t>=m)
    {
        int ans=solve();
        if(ans<min_ans&&ans!=-1)
            min_ans=ans;
    }
    else
    {
        for(int i=0;i<=1;i++)
        {
            x[t]=i;
            fun(t+1);
        }
    }
}
int main()
{
    int T;
    //freopen("in.cpp","r",stdin);
    while(scanf("%d",&T)!=EOF)
    {
        while(T--)
        {
            count_line=0;
            min_ans=INTMAX;
            scanf("%d%d",&n,&m);
            for(int i=0;i<m;i++)
            {
                scanf("%d%d",&l[i].num,&l[i].price);
                for(int j=0;j<l[i].num;j++)
                {
                    scanf("%d",&l[i].node[j]);
                    l[i].node[j]--;
                }
            }
            for(int i=0;i<n;i++)
            {
                scanf("%d%d",&p[i].x,&p[i].y);
            }
            for(int i=0;i<n;i++)
            {
                for(int j=i+1;j<n;j++)
                {
                    if(i==j)
                        continue;
                    line[count_line].u=i;
                    line[count_line].v=j;
                    line[count_line].w=cal(p[i],p[j]);
                    count_line++;
                }
            }
            fun(0);
            printf("%d\n",min_ans);
            if(T!=0) printf("\n");
        }
    }
    return 0;
}
时间: 2024-08-06 10:17:58

UVA 1151 Buy or build(并查集之六)的相关文章

UVA 1151 Buy or Build

先求出原图的最小生成树,然后枚举买哪些套餐,把一个套餐内的点相当与边权为0,直接用并查集缩点.正确性是基于一个贪心, 在Kruskal中,对于没有进入最小生成树的边,排序在它前面的边不会减少. 边比较多,用prim求最小生成树,效果比Kruskal好,枚举套餐的时候在用Kruskal. #include<bits/stdc++.h> using namespace std; const int maxn = 1005; int n,q; int C[9]; vector<int>

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

链接: https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3592 题意: 平面上有n个点(1≤n≤1000),你的任务是让所有n个点连通.为此,你可以新建一些边,费用等于两个端点的欧几里德距离的平方.另外还有q(0≤q≤8)个"套餐"可以购买,如果你购买了第i个套餐,该套餐中的所有结点将变得相互连通.第i个套餐的花费为C

uva 1151 - Buy or Build poj 2784 Buy or Build(最小生成树)

也是简单的最小生成树算法 不过添加了一些新的东西,需要对最小生成树算法 以及其中的 并查集的使用 有一些比较深入的理解. 处理问题的方法也有些复杂 #include<cstdio> #include<cstring> #include<vector> #include<algorithm> using namespace std; const int maxn = 1005; struct point { int x; int y; }pp[maxn]; s

UVA 1151 Buy or Build (MST最小生成树,kruscal,变形)

题意:要使n个点之间能够互通,要使两点直接互通需要耗费它们之间的欧几里得距离的平方的权(注意不需要开方的),这说明每两个点都可以使其互通.接着又q个套餐可以选,一旦选了这些套餐,他们所包含的点自动就连起来了,所需要做的就是连上还未通的即可,q<=8.可以多买.求最小生成树所需的代价. 思路:与普通求MST不同的就是多了套餐,而且还可以多买.每个套餐有买或不买两种可能,那么有28种可能,即256种. 如果不买套餐,至少需要求1次MST是确定的,这个复杂度已经是O(n*n)了.还得考虑哪些餐套可以搭

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

题意:给定n个点,你的任务是让它们都连通.你可以新建一些边,费用等于两点距离的平方(当然越小越好),另外还有几种“套餐”,可以购买,你购买的话,那么有些边就可以连接起来, 每个“套餐”,也是要花费的,让你求出最少花费. 析:首先想到的是把所有情况都考虑算一下,然后找出最少的,先算没有“套餐”的,然后算有的,用二进制枚举的话,总时间复杂度为O(2qn2+n2logn),这个时间复杂度太大了吧,肯定会超时, 那么我们就可以优化一下,首先先算出来最小生成树,并且把每条边都保存下来,那么加了“套餐”之后

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

题意:给出n个点的坐标,现在需要让这n个点连通,可以直接在点与点之间连边,花费为两点之间欧几里得距离的平方,也可以选购套餐,套餐中所含的点是相互连通的 问最少的花费 首先想kruskal算法中,被加入的边已经是最优的了,所以当选择完套餐后,之前被丢弃的边也不会再进入最小生成树 然后就可以先求一次原图的最小生成树,保存下进入最小生成树的n-1条边 再枚举选择的套餐的情况,再求最小生成树,这里用的二进制法枚举 最后维护一个最小值就可以了 思路虽然看懂了,可是代码根本就写不出来,看着标程写的,最后还是

1151 - Buy or Build(二进制枚举子集 + 并查集)

这题LRJ书上翻译的有问题,书上说两点之间的cost是两点的欧几里得距离,而题目要求两点的距离是两点欧几里得距离的平方. 其余就没什么好说的了,裸的并查集,需要注意的就是二进制枚举子集的问题. 二进制枚举子集: for(int i = 0 ; i < (1 << s) ; i++){ /*s是集合元素的个数*/ for(int j = 0 ; j < s ; j++){ if(!(s >> j) & 1) continue; else{ } } } 140548

UVA 1455 - Kingdom(线段树+并查集)

UVA 1455 - Kingdom 题目链接 题意:给定一些城市坐标点,连在一起的城市称为一个州,现在用两种操作,road表示把城市a,b建一条路,line表示询问一个y轴上穿过多少个州,和这些州共包含多少个城市 思路:利用并查集维护每个州的上界和下界还有城市个数,然后每次加进一条路的时候,根据两个集合的位置可以处理出区间的州和城市数如何进行加减,然后利用线段树搞就可以了 代码: #include <cstdio> #include <cstring> #include <

uva 11987 Almost Union-Find (并查集)

题目大意: 三个操作. 1. 合并两个集合 2.把第一个元素放到第二个集合里 3.输出集合的数量和和.. 思路分析: 要用p记录这个元素所在集合编号,然后用编号建立并查集. #include <cstdio> #include <iostream> #include <algorithm> #include <cstring> using namespace std; typedef long long LL; int set[111111]; int cn