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

原创 2015年07月10日 11:22:50

链接:

#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\n",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;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

【最小乘积生成树详解】【BZOJ2395】

题意:设每个点有x,y两个权值,求一棵生成树,使得sigma(x[i])*sigma(y[i])最小。   设每棵生成树为坐标系上的一个点,sigma(x[i])为横坐标,sigma(y[i])为...

bzoj 2395(最小乘积生成树)

参考别人的blog:点击打开链接 #include #include #include #include #include #include #include #include #...

【最小乘积生成树 】bzoj2395

bzoj2395          以前听基哥讲的时候就没怎么懂,以为好难写好难写    //  其实不难写,只是有点难调。          利用数形结合的思想,每棵生成树在坐标系上对应的是点(...
  • cjoilmd
  • cjoilmd
  • 2012年02月18日 20:22
  • 2318

bzoj2395: [Balkan 2011]Timeismoney

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2395 思路:与bzoj3571类似的思想,只是内部是kruskal而已 其实数据范围最大是会...

2395: [Balkan 2011]Timeismoney

2395: [Balkan 2011]TimeismoneyTime Limit: 10 Sec Memory Limit: 128 MB Submit: 659 Solved: 359 [S...

给定A, B两个整数,不使用除法和取模运算,求A/B的商和余数

给定A, B两个整数,不使用除法和取模运算,求A/B的商和余数。 1.   最基本的算法是,从小到大遍历: for (i = 2 to A -1)          if (i * B > A)...

利用K-means聚类算法根据经纬度坐标对中国省市进行聚类

K-means聚类算法是一种非层次聚类算法,在最小误差的基础上将数据划分了特定的类,类间利用距离作为相似度指标,两个向量之间的距离越小,其相似度就越高。程序读取全国省市经纬度坐标,然后根据经纬度坐标进...

Radon变换理论介绍与matlab实现--经验交流

本人最近在研究Radon变换,在查阅了各种资料之后在此写下个人的理解,希望与各位牛牛进行交流共同进步,也使得理解更加深刻些。 Radon变换的本质是将原来的函数做了一个空间转换,即,将原来的XY平...

CT图像重建技术

由于csdn贴图不方便,并且不能上传附件,我把原文上传到了资源空间CT图像重建技术 1.引言 计算机层析成像(Computed Tomography,CT)是通过对物体进行不同角度的射线投影测量而...

Matlab绘图-很详细,很全面

Matlab绘图强大的绘图功能是Matlab的特点之一,Matlab提供了一系列的绘图函数,用户不需要过多的考虑绘图的细节,只需要给出一些基本参数就能得到所需图形,这类函数称为高层绘图函数。此外,Ma...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:【BZOJ2395】【Balkan 2011】Timeismoney 最小乘积生成树
举报原因:
原因补充:

(最多只允许输入30个字)