BZOJ 2395 Timeismoney

Posted on 2017-01-21 22:05  ziliuziliu  阅读(219)  评论(0编辑  收藏  举报

最小乘积生成树。

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

递归求解。

#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\n",ans.a,ans.b);
    return 0;
}