• 【BZOJ2395】【Balkan 2011】Timeismoney 最小乘积生成树


    链接:

    #include <stdio.h>
    int main()
    {
        puts("转载请注明出处[辗转山河弋流歌 by 空灰冰魂]谢谢");
        puts("网址:blog.csdn.net/vmurder/article/details/46828379");
    }

    题解:

    裸最小乘积生成树。

    最小乘积生成树定义:

    有一张n个点m条边的无向图,每条边有k个权值。


    如今要取一个边集M使得其将全部点连通。并使
    ki=1(jMjcost(j,vali)) 最小
    即个边集的每一种边权的总和的乘积最小。

    比方:
    k=1时,就是裸最小生成树。
    k=2时。就是要使 [边集的权值1的和]*[边集的权值2的和] 最小。

    最小乘积生成树的一种求法:

    广义上的说法(不是必需看,或者看完以下的再来看这个就好)

    首先我们能够把每种生成树想成一个k维的点,第i维的坐标即那一维上权值的和。

    然后我们能够先求出每一维坐标最小的一棵生成树(裸上最小生成树就好)。
    然后得到一个k-1维的面,然后我们来求一下离这个面最远的点,然后分治下去……据说期望非常快……

    二维最小乘积生成树的求法:

    给每一棵生成树都定义两个权值X、Y,当中X为其包括的全部边的权值x的和,Y为其包括的全部边的权值y的和,那么我们能够把每一种生成树看成一个坐标。

    我们先求出坐标x最小的一棵生成树。再求出坐标y最小的一棵生成树。
    然后我们能够考虑。最优的点一定在下凸包上【证明一】,然后我们要进行一个不断向左下拓展点的过程:对于两个点A、B形成的直线,我们能够找出在这条直线左下的最远的点C。然后对AC、CB递归做相同的过程,直到找不到一个在左下的点C为止。

    然后怎样找一个最远的点C呢?
    我们能够发现既然有一条边固定,那么最好还是把“最远”转化成三角形面积最大。这个用叉积搞一搞,,然后会推出公式面积跟点C有关的部分= Ax+By ,,那么我们把全部边的权值 x 乘上 A ,权值 y 乘上 B 就好了,,,AB 是啥自己求去!

    【题外】:三维的,就是离一个平面最远。转化成体积最大。递归分成三层而非两层,。。,。然后四维,甚至更高维,感觉应该是同理的吧?

    关于上文中【证明一】

    每一个点xi,yi 都相应一条函数曲线 ki=xiyi,而随意两不同 ki ,它们的函数曲线是不交的(有交的话则存在一点 (xj,yj) 使得 ki=xjyj=kjki!=kj 成立,显然这是悖论),那么显然最长处肯定不会在凸包内,否则必有凸包上一点比它优。

    那么会不会求出这个某种意义上的凸包后,最长处在凸包外,却没被找到呢?
    不会。
    若有这样的情况。此点必定在凸包上某边的左下方。。然后一定会被找出来。。

    代码:

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define N 205
    #define M 10100
    #define inf 0x3f3f3f3f
    using namespace std;
    struct Eli
    {
        int u,v,a,b,c;
        void read()
        {
            scanf("%d%d%d%d",&u,&v,&a,&b);
            u++,v++;
        }
    }e[M];
    inline bool cmpa(const Eli &a,const Eli &b){return a.a<b.a;}
    inline bool cmpb(const Eli &a,const Eli &b){return a.b<b.b;}
    inline bool cmpc(const Eli &a,const Eli &b){return a.c<b.c;}
    struct Point
    {
        int x,y;
        void print(){printf("%d %d
    ",x,y);}
        Point(int _x=0,int _y=0):x(_x),y(_y){}
        bool operator < (const Point &A)const
        {
            unsigned int p=  x;p*=  y;
            unsigned int q=A.x;q*=A.y;
            return p==q?

    x<A.x:p<q; } }ans,now,mina,minb; int f[N],n,m; int find(int x){return f[x]==x?x:f[x]=find(f[x]);} Point Kruscal() { int i,fa,fb; now=Point(0,0); for(i=1;i<=n;i++)f[i]=i; for(i=1;i<=m;i++) { fa=find(e[i].u),fb=find(e[i].v); if(fa!=fb) { f[fb]=fa; now.x+=e[i].a; now.y+=e[i].b; } } if(now<ans)ans=now; return now; } inline int xmul(const Point &A,const Point &B,const Point &C) {return (C.y-A.y)*(B.x-A.x)-(C.x-A.x)*(B.y-A.y);} void work(const Point &A,const Point &B) { for(int i=1;i<=m;i++) e[i].c=e[i].b*(A.x-B.x)+e[i].a*(B.y-A.y); sort(e+1,e+m+1,cmpc); Point C=Kruscal(); if(xmul(A,B,C)<=0)return ; work(A,C),work(C,B); } int main() { // freopen("test.in","r",stdin); int i,j,k; int a,b,c; ans=Point(inf,inf); scanf("%d%d",&n,&m); for(i=1;i<=m;i++)e[i].read(); sort(e+1,e+m+1,cmpa),mina=Kruscal(); sort(e+1,e+m+1,cmpb),minb=Kruscal(); work(minb,mina),ans.print(); fclose(stdin); fclose(stdout); return 0; }

  • 相关阅读:
    HBase 负载均衡
    HBase的写事务,MVCC及新的写线程模型
    HBase RegionServer宕机处理恢复
    分布式事务实现-Percolator
    MVC框架
    06-JS中li移动第二种形式
    05-JS中li移动第一种形式
    04-JS中文档碎片
    03-JS中添加节点
    02-JS中父节点
  • 原文地址:https://www.cnblogs.com/claireyuancy/p/7364145.html
Copyright © 2020-2023  润新知