• UVa 1151 Buy or Build(最小生成树+枚举子集)


    题意:

      在平面上有n个点,要让所有n个点都连通,所以你要构造一些边来连通他们,连通的费用等于两个端点的欧几里得距离的平方。另外还可以选择q个套餐,可以购买,套餐内的所有点将会被连通。求最小花费。

    题解:

      如果不选择套餐的话,就是裸的MST。现在有了套餐可以选择,可以选择多个,那么就把它们(套餐里的点)先加入到生成树里,用位运算枚举集合的子集。

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    using namespace std;
    const int maxn=1005,INF=0x3f3f3f3f;
    int n,cnt;
    int par[maxn];
    struct edge
    {
        int u,v,cost;
        bool operator <(const edge& a) const//重载<运算符
        {
            return cost<a.cost;
        }
    }es[maxn*maxn];
    struct point
    {
        int x,y;
    }p[maxn];
    struct buy
    {
        int num;//套餐的点的数量
        int cost;//套餐的花费
        int a[maxn];//套餐里的点
    }bu[8];
    void init()
    {
        for(int i=1;i<=n;i++)
            par[i]=i;
    }
    int find(int x)
    {
        return x==par[x]?x:par[x]=find(par[x]);
    }
    void unite(int x,int y)
    {
        x=find(x);
        y=find(y);
        if(x!=y)
            par[x]=y;
    }
    bool same(int x,int y)
    {
        return find(x)==find(y);
    }
    int  dis(point a,point b)
    {
        return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
    }
    int kruskal()
    {
        int res=0;
        for(int i=0;i<cnt;i++)
        {
            edge e=es[i];
            if(!same(e.u,e.v))
            {
                res+=e.cost;
                unite(e.u,e.v);
            }
        }
        return res;
    }
    int main()
    {
        int t;
        cin>>t;
        while(t--)
        {
            int q;
            cin>>n>>q;
            for(int i=0;i<q;i++)
            {
                cin>>bu[i].num>>bu[i].cost;
                for(int j=0;j<bu[i].num;j++)
                    cin>>bu[i].a[j];
            }
            cnt=0;
            for(int i=1;i<=n;i++)
            {
                cin>>p[i].x>>p[i].y;
            }
            for(int i=1;i<n;i++)
                for(int j=i+1;j<=n;j++)
                {
                    es[cnt].u=i;
                    es[cnt].v=j;
                    es[cnt++].cost=dis(p[i],p[j]);
                }
            sort(es,es+cnt);
            int ans=INF;
            for(int i=0;i<(1<<q);i++)//枚举子集
            {
                init();//每次选择套餐的时候,对并查集初始化
                int temp=i;
                int mst=0;
                for(int j=0;j<q;j++)
                {
                    if(temp&1)
                    {
                        mst+=bu[j].cost;
                        for(int k=1;k<bu[j].num;k++)
                        {
                            unite(bu[j].a[k],bu[j].a[0]);
                        }
                    }
                    temp>>=1;
                }
                mst+=kruskal();
                ans=min(ans,mst);
            }
            cout<<ans<<endl;
            if(t)
                cout<<endl;
        }
        return 0;
    }

      

  • 相关阅读:
    玄学最短路算法——Ex Floyd
    题解 CF785E 【Anton and Permutation】
    题解 P1825 【[USACO11OPEN]玉米田迷宫Corn Maze】
    实现非递归树链剖分
    题解 P3423 【[POI2005]BAN-Bank Notes】
    题解 P3871 【[TJOI2010]中位数】
    【带修改的主席树】理解题解 (P2617 【Dynamic Rankings】题解)
    快速计算高精乘低精---低精优化高精
    了解 yaml文件格式
    com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'test.ac_flight' doesn't exist
  • 原文地址:https://www.cnblogs.com/orion7/p/7411388.html
Copyright © 2020-2023  润新知