zoukankan      html  css  js  c++  java
  • BZOJ 2395 Timeismoney

    最小乘积生成树。

    本质上是把生成树作为平面上的点,那么答案一定在下凸壳上。

    递归求解。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define maxv 250
    #define maxe 10050
    #define inf 1000000007
    using namespace std;
    int n,m,a,b,c,d,father[maxv];
    struct edge
    {
        int x,y,a,b,c;
        edge (int x,int y,int a,int b):x(x),y(y),a(a),b(b) {}
        edge () {}
    }e[maxe];
    struct point
    {
        int a,b;
        point (int a,int b):a(a),b(b) {}
        point () {}
        friend point operator - (const point & x,const point & y)
        {
            return point(x.a-y.a,x.b-y.b);
        }
        friend int operator * (const point & x,const point & y)
        {
            return x.a*y.b-x.b*y.a;
        }
        friend bool operator < (const point &x,const point & y)
        {
            long long ans1=(long long)x.a*x.b,ans2=(long long)y.a*y.b;
            return ans1==ans2?x.a<y.a:ans1<ans2;
        }
    }ans;
    bool cmp1(const edge & x,const edge & y)
    {
        if (x.a!=y.a) return x.a<y.a;
        return x.b<y.b;
    }
    bool cmp2(const edge & x,const edge & y)
    {
        if (x.b!=y.b) return x.b<y.b;
        return x.a<y.a;
    }
    bool cmp3(const edge & x,const edge & y)
    {
        if (x.c!=y.c) return x.c<y.c;
        else if (x.a!=y.a) return x.a<y.a;
        else return x.b<y.b;
    }
    int getfather(int x)
    {
        if (x!=father[x]) father[x]=getfather(father[x]);
        return father[x];
    }
    point kruskal()
    {
        point ret=point(0,0);
        for (int i=1;i<=n;i++) father[i]=i;
        for (int i=1;i<=m;i++)
        {
            int x=e[i].x,y=e[i].y;
            int f1=getfather(x),f2=getfather(y);
            if (f1!=f2) {father[f1]=f2;ret.a+=e[i].a;ret.b+=e[i].b;}
        }
        if (ret<ans) ans=ret;
        return ret;
    }
    void min_product_tree(point A,point B)
    {
        point C;
        for (int i=1;i<=m;i++) e[i].c=(A.b-B.b)*e[i].a+(B.a-A.a)*e[i].b;
        sort(e+1,e+m+1,cmp3);C=kruskal();
        if ((A-B)*(C-B)<=0) return;
        min_product_tree(A,C);min_product_tree(C,B);
    }
    int main()
    {
        ans=point(inf,inf);
        scanf("%d%d",&n,&m);
        for (int i=1;i<=m;i++)
        {
            scanf("%d%d%d%d",&a,&b,&c,&d);a++;b++;
            e[i]=edge(a,b,c,d);
        }
        point A,B,C;
        sort(e+1,e+m+1,cmp1);A=kruskal();
        sort(e+1,e+m+1,cmp2);B=kruskal();
        min_product_tree(A,B); 
        printf("%d %d
    ",ans.a,ans.b);
        return 0;
    }
  • 相关阅读:
    编程命名规范化
    傻孩子菜单框架(转)
    《数据结构》示范程序树的长子-兄弟表示法
    keil中编译时出现*** ERROR L107: ADDRESS SPACE OVERFLOW
    单片机C语言下LCD多级菜单的一种实现方法
    指针函数与函数指针的区别
    LCD1602汉字、自定义字符取模
    FFmpeg纯净版解码 av_parser_parse2
    ffmpeg 内存读写相关
    AudioSpecificConfig
  • 原文地址:https://www.cnblogs.com/ziliuziliu/p/6337966.html
Copyright © 2011-2022 走看看