zoukankan      html  css  js  c++  java
  • bzoj 2395 [Balkan 2011]Timeismoney——最小乘积生成树

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2395

    如果把 ( sum t ) 作为 x 坐标,( sum c ) 作为 y 坐标,则每棵生成树都是二维平面上的一个点。

    答案是二维平面上的一个下凸壳。先求出只考虑 t 的最小生成树和只考虑 c 的最小生成树,它们就是凸壳的两端。

    已知两端,考虑递归下去,则要找到距离这两端构成的直线最远的点。

    这就是点到直线的距离,等价于三个点组成的三角形面积最小;考虑叉积公式,得出面积关于要找的点的 x , y 坐标的式子,形如 A*x + B*y ;

    给边权乘上系数,就能求最小生成树得到该点;如果面积是负的,就求最小生成树,否则求最大生成树。

    判断是否不用再往下递归,本来写的是找到的那个点就是两端点之一,结果T了;写成找到的那个点在两端点的连线上就可以了。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define ll long long
    using namespace std;
    const int N=205,M=1e4+5;
    int n,m,fa[N],dep[N];
    struct Ed{int t,c,w,x,y;}ed[M];
    struct Node{
      int t,c;ll w;
      Node(){t=c=w=0;}
      bool operator== (const Node &b)const
      {return t==b.t&&c==b.c;}
    }ans;
    int rdn()
    {
      int ret=0;bool fx=1;char ch=getchar();
      while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();}
      while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
      return fx?ret:-ret;
    }
    void frh(Node p){if(p.w<ans.w||(p.w==ans.w&&p.c<ans.c))ans=p;}
    bool cmp(Ed u,Ed v){return u.w<v.w;}
    int fnd(int a){return fa[a]==a?a:fa[a]=fnd(fa[a]);}
    ll Cross(int x1,int y1,int x2,int y2)
    {return (ll)x1*y2-(ll)x2*y1;}
    Node calc(int t0,int t1)
    {
      for(int i=1;i<=m;i++)ed[i].w=(ll)t0*ed[i].t+(ll)t1*ed[i].c;
      sort(ed+1,ed+m+1,cmp);
      memset(dep,0,sizeof dep);
      for(int i=1;i<=n;i++)fa[i]=i;
      Node ret;
      for(int i=1,u,v,cnt=0;i<=m;i++)
        {
          if((u=fnd(ed[i].x))==(v=fnd(ed[i].y)))continue;
          if(dep[u]>dep[v])swap(u,v);
          fa[u]=v;if(dep[u]==dep[v])dep[v]++;
          ret.t+=ed[i].t;ret.c+=ed[i].c;
          cnt++;if(cnt==n-1)break;
        }
      ret.w=(ll)ret.t*ret.c;
      return ret;
    }
    void solve(Node p0,Node p1)
    {
      int st=p1.c-p0.c,sc=p0.t-p1.t;
      Node res=calc(st,sc);frh(res);
      //  if(res==p0||res==p1)return;
      if(Cross(p1.t-res.t,p1.c-res.c,p0.t-res.t,p0.c-res.c)>=0)return;
      solve(p0,res); solve(res,p1);
    }
    int main()
    {
      n=rdn();m=rdn();
      for(int i=1;i<=m;i++)
        ed[i].x=rdn()+1,ed[i].y=rdn()+1,ed[i].t=rdn(),ed[i].c=rdn();
      ans.t=ans.c=1e9;ans.w=1e18;
      Node p0=calc(0,1),p1=calc(1,0);
      frh(p0);frh(p1);
      solve(p0,p1);
      printf("%d %d
    ",ans.t,ans.c);
      return 0;
    }
  • 相关阅读:
    LeetCode-216 Combination Sum III
    LeetCode-214 Shortest Palindrome
    LeetCode-212 Word Search II
    LeetCode-211 Add and Search Word
    LeetCode-210 Course Schedule II
    LeetCode-209 Minimum Size Subarray Sum
    LeetCode-208 Implement Trie (Prefix Tree)
    LeetCode-207 Course Schedule
    JavaEE--Mybatis学习笔记(四)--单表的CURD 补充
    JavaEE--Mybatis学习笔记(三)--单表的CURD
  • 原文地址:https://www.cnblogs.com/Narh/p/10131969.html
Copyright © 2011-2022 走看看