• bzoj 2395 Timeismoney —— 最小乘积生成树


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

    参考博客:https://www.cnblogs.com/autsky-jadek/p/3959446.html

    但复杂度不太会算;

    递归边界不要取两个点相等,而是叉积>=0 。

    代码如下:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    int const xn=205,xm=1e4+5;
    int n,m,fa[xn],dis[xn];
    ll ansx,ansy;
    struct N{
      int u,v,a,b; ll w;
      bool operator < (const N &y) const
      {return w<y.w;}
    }ed[xm];
    struct P{
      ll x,y;
      P(ll x=0,ll y=0):x(x),y(y) {}
    };
    P operator - (const P &A,const P &B){return P(A.x-B.x,A.y-B.y);}
    ll cross(P A,P B){return A.x*B.y-A.y*B.x;}
    int rd()
    {
      int ret=0,f=1; char ch=getchar();
      while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();}
      while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
      return f?ret:-ret;
    }
    int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
    void uni(int x,int y)
    {
      if(dis[x]==dis[y])fa[x]=y,dis[y]++;
      else if(dis[x]<dis[y])fa[x]=y;
      else fa[y]=x;
    }
    P kruskal()
    {
      int cnt=0; P ret=P(0,0);
      memset(dis,0,sizeof dis);
      for(int i=1;i<=n;i++)fa[i]=i;
      sort(ed+1,ed+m+1);
      for(int i=1;i<=m;i++)
        {
          int x=find(ed[i].u),y=find(ed[i].v);
          if(x==y)continue;
          ret.x+=ed[i].a; ret.y+=ed[i].b;
          uni(x,y); cnt++;
          if(cnt==n-1)break;
        }
      return ret;
    }
    bool eql(P A,P B){return A.x==B.x&&A.y==B.y;}
    void solve(P A,P B)
    {
      for(int i=1;i<=m;i++)ed[i].w=ed[i].b*(B.x-A.x)+ed[i].a*(A.y-B.y);
      P C=kruskal();
      if(cross(B-A,C-A)>=0)return;//>=0
      //if(eql(A,C)||eql(B,C))return;
      if((C.x*C.y<ansx*ansy)||(C.x*C.y==ansx*ansy&&C.x<ansx))ansx=C.x,ansy=C.y;
      solve(A,C); solve(C,B);
    }
    int main()
    {
      n=rd(); m=rd();
      for(int i=1;i<=m;i++)
        ed[i].u=rd()+1,ed[i].v=rd()+1,ed[i].a=rd(),ed[i].b=rd();
      for(int i=1;i<=m;i++)ed[i].w=ed[i].a;
      P A=kruskal();
      for(int i=1;i<=m;i++)ed[i].w=ed[i].b;
      P B=kruskal();
      if((A.x*A.y<B.x*B.y)||(A.x*A.y==B.x*B.y&&A.x<B.x))ansx=A.x,ansy=A.y;
      else ansx=B.x,ansy=B.y;
      solve(A,B);
      printf("%lld %lld
    ",ansx,ansy);
      return 0;
    }
  • 相关阅读:
    Android MediaRecorder实现暂停断点录音功能
    Sqlite 数据库分页查询(ListView分页显示数据)
    Android 一键直接查看Sqlite数据库数据
    Android setTag()/getTag()
    sqlite3常用命令&语法
    Android 编辑框插入表情图片
    奇怪++操作
    hdu5024(dp)
    Windows Azure VM两shut down 道路
    android简单的计算器
  • 原文地址:https://www.cnblogs.com/Zinn/p/10131771.html
Copyright © 2020-2023  润新知