• 2019.3.16 最小生成树之城市改造


    题目描述
    作为规划局长的你接到了城市C的改造任务:城市中有n个标志性建筑,要在这n个标志性建筑之间修建双向道路,使得这n个标志性建筑之间相互连通,以最大程度地方便游客来访。由于市政府资金有限,所以希望成本尽可能低。建设费用有两种支付方式:
    1. 施工公司给出m种套餐供选择,每种套餐可以将方案中的所有标志性建筑连通,总花费为Ci;
    2. 单独铺设两个标志物之间道路,费用为两个标志物之间的欧式距离的平方。
    现在要求你选择最佳的建设方案(可以选择任意个套餐以及铺设任意条道路)。
    输入
    输入第一行包括两个整数n和m,分别表示标志物的数量和可选套餐数量。(以下用1~n分别表示n个标志物)
    然后用m行表示m个套餐,每行第一个数字表示套餐可以连接的标志物数量,第二个数字表示该套餐的费用(费用不高于200w万元),后面的数字分别表示该套餐连通的标志物编号。
    最后n行表示n个标志物的坐标,每行用空格隔开的两个数字(0~3000),分别表示横纵坐标。
    输出
    输出一个数字,表示改造城市的最低花费。
    样例输入
    7 3
    2 4 1 2
    3 3 3 6 7
    3 9 2 4 5
    0 2
    4 0
    2 0
    4 2
    1 3
    0 5
    4 4
    样例输出
    17
    提示
    【数据范围】
    对于100%的数据,1<=n<=1000,0<=m<=8。

    省选NOI- QAQ
    其实就是一个最小生成树加枚举
    由于套餐数据较小 选择先枚举套餐再添加边形成最小生成树
    剪枝:
    (1)将套餐是否选择用2进制保存,是则为1,否则为0;
    (2)Kruscal算法中选择先将每个套餐合并为同一祖先,再通过一个点将两个套餐合并。
    上代码
    #include<iostream>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    long long n,m,pre[1005],link[15],tmp,book[15][1005],x[1005],y[1005],cnt=1;
    long long ans=0x3f3f3f3f;
    static const long long numm[9]={1,2,4,8,16,32,64,128,256};
    struct edge
    {
        long long u,v;
        long long w;
        bool operator<(const edge& o) const
        {
            return w<o.w;//重载小于运算符,将边按照边权排序
        }
    }e[1000005];
    int f(long long a)
    {
        if(pre[a]==a)return a;
        return pre[a]=f(pre[a]);
    }//查找祖先
    void u(long long a,long long b)
    {
        long long c=f(a),d=f(b);
        if(pre[c]!=pre[d])pre[c]=pre[d];
    }//合并
    void Kruscal()//最小生成树
    {
        long long a[15];
        for(long long i=0;i<numm[m];i++)
        {
            for(long long j=1;j<=n;j++)pre[j]=j;//初始化祖先
            long long tmp=i,anss=0;
            for(long long j=m;j>=1;j--)a[j]=tmp%2,tmp/=2;//状压
            for(long long j=1;j<=m;j++)
            {
                if(a[j]==1)
                {
                    long long temp=2;
                    while(1)
                    {
                        u(book[j][temp-1],book[j][temp]);//合并套餐内部
                        temp++;
                        if(book[j][temp]==0)break;
                    }
                    anss+=link[j];
                }
            }
            for(long long j=1;j<=cnt;j++)//加边形成最小生成树
            {
                long long uu=e[j].u,vv=e[j].v;
                if(f(uu)!=f(vv))
                {
                    u(uu,vv);
                    anss+=e[j].w;
                }
            }
            ans=min(ans,anss);//选择费用最小值
        }
    }
    int main()
    {
        scanf("%lld%lld",&n,&m);
        for(long long i=1;i<=m;i++)
        {
            long long num;
            scanf("%lld%lld",&num,&link[i]);//套餐内建筑数目与套餐价格
            for(long long j=1;j<=num;j++)scanf("%lld",&book[i][j]);
        }
        for(long long i=1;i<=n;i++)scanf("%lld%lld",&x[i],&y[i]);
        for(long long i=1;i<=n;i++)
        {
            for(long long j=1;j<=n;j++)
            {
                if(i==j)continue;
                e[cnt].u=i,e[cnt].v=j;
                e[cnt].w=(x[j]-x[i])*(x[j]-x[i])+(y[j]-y[i])*(y[j]-y[i]);//初始化边权
                cnt++;
            }
        }
        sort(e+1,e+cnt);
        cnt--;//将cnt置为边数
        Kruscal();
        printf("%lld",ans);
        return 0;
    }
    /*====年轻人,瞎搞是出不了省一的,这就是现实====*/
  • 相关阅读:
    C#可空类型 T?
    Unity踩过的坑
    Unity可视化数据:创建图表
    unity3d屏幕截图功能
    unity3d插入android有米广告
    Unity调用PC摄像头
    使用Unity的50个建议
    Unity3d流光效果
    unity3d中的Quaternion.LookRotation
    Unity3D中可重载虚函数的总结
  • 原文地址:https://www.cnblogs.com/qxds/p/10584144.html
Copyright © 2020-2023  润新知