首页 > 其他分享 >最小乘积生成树

最小乘积生成树

时间:2023-04-19 17:57:21浏览次数:31  
标签:AB overrightarrow int 边权 最小 times 生成 include 乘积

感觉上次写知识点已经是若干年前了。

板子是 P5540。

把生成树的 \(\sum a,\sum b\) 看做坐标 \((x,y)\) 扔到二维平面上,那么我们就相当于找一个 \(x\times y\) 最小的点。这个点显然在凸包上。当然我们不可能把所有点找出来跑凸包。那我们想办法只扫可能成为答案的点,即只找一个凸壳:

  1. 找到和 \(x\) 轴、\(y\) 轴最近的点。这个简单,可以直接以 \(a,b\) 为边权分别跑一遍凸包。设以 \(a\) 为边权得到点 \(A\),以 \(b\) 为边权得到点 \(B\)。

  2. 找到 \(AB\) 左下方且距离 \(AB\) 最远的点 \(C\)。最远可以变成 \(S_{\triangle ABC}\) 最大。那么 \(S_{\triangle ABC}=-\frac{\overrightarrow{AB}\times\overrightarrow{AC}}2\),最小化 \(\overrightarrow{AB}\times\overrightarrow{AC}\) 即可。

    化一下式子:

    \[\begin{aligned} \overrightarrow{AB}\times\overrightarrow{AC}=&(x_B-x_A)(y_C-y_A)-(x_C-x_A)(y_B-y_A)\\ =&(x_B-x_A)y_C+(y_A-y_B)x_C-(x_B-x_A)y_A+(y_B-y_A)x_A \end{aligned} \]

    最小化前两项,可以直接把边权设为 \((x_B-x_A)b_i+(y_A-y_B)a_i\) 跑最小生成树。

  3. 回到第二步递归向下分治处理。如果得到的 \(C\) 在 \(AB\) 上边说明 \(C\) 不在凸包上,返回即可。

\(n\) 个点的凸包期望大小是 \(O(\sqrt{\ln n})\) 的,所以复杂度不会证。

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
int n,m;
struct gra{
    int u,v,w,a,b;
    bool operator<(const gra&s)const{
        return w<s.w;
    }
}edge[10010];
struct node{
    int x,y;
    node operator+(const node&s)const{
        return {x+s.x,y+s.y};
    }
    node operator-(const node&s)const{
        return {x-s.x,y-s.y};
    }
    int operator^(const node&s)const{
        return x*s.y-y*s.x;
    }
}ans;
int fa[210];
int find(int x){
    return x==fa[x]?fa[x]:fa[x]=find(fa[x]);
}
void merge(int x,int y){
    fa[find(y)]=find(x);
}
node kruskal(){
    node x={};
    for(int i=1;i<=n;i++)fa[i]=i;
    sort(edge+1,edge+m+1);
    for(int i=1;i<=m;i++){
        if(find(edge[i].u)!=find(edge[i].v)){
            merge(edge[i].u,edge[i].v);
            x=x+(node){edge[i].a,edge[i].b};
        }
    }
    long long ret=1ll*ans.x*ans.y,tmp=1ll*x.x*x.y;
    if(tmp<ret||(tmp==ret&&x.x<ans.x))ans=x;
    return x;
}
void solve(node x,node y){
    for(int i=1;i<=m;i++)edge[i].w=edge[i].b*(y.x-x.x)+edge[i].a*(x.y-y.y);
    node ret=kruskal();
    if(((y-x)^(ret-x))>=0)return;
    solve(x,ret);solve(ret,y);
}
int main(){
    scanf("%d%d",&n,&m);ans.x=ans.y=0x3f3f3f3f;
    for(int i=1;i<=m;i++){
        scanf("%d%d%d%d",&edge[i].u,&edge[i].v,&edge[i].a,&edge[i].b);
        edge[i].u++;edge[i].v++;
    }
    for(int i=1;i<=m;i++)edge[i].w=edge[i].a;
    node x=kruskal();
    for(int i=1;i<=m;i++)edge[i].w=edge[i].b;
    node y=kruskal();
    solve(x,y);
    printf("%d %d\n",ans.x,ans.y);
    return 0;
}

另一个题是[HNOI2014]画框,把最小生成树换成费用流就行了。

标签:AB,overrightarrow,int,边权,最小,times,生成,include,乘积
From: https://www.cnblogs.com/gtm1514/p/17334147.html

相关文章

  • AspNetCore 成长杂记(一):JWT授权鉴权之生成JWT(其一)
    引子最近不知怎么的,自从学了WebAPI(为什么是这个,而不是MVC,还不是因为MVC的Razor语法比较难学,生态不如现有的Vue等框架,webapi很好的结合了前端生态)以后,使用别人的组件一帆风顺,但是不知其意,突然很想自己实现一个基于的JWT认证服务,来好好了解一下这个内容。起步自从Session-Cooki......
  • 论文阅读记录2——条件生成对抗网络读后归纳
     方法:具体的来说,我们可以在生成模型G和判别模型D中同时加入条件约束来引导数据的生成过程。条件可以是任何补充的信息,如类标签,其它模态的数据等。然后这样的做法应用也很多,比如图像标注,利用text生成图片等等。原因:因为原始的GAN过于自由,训练会很容易失去方向,从而导致不稳定......
  • C#生成不重复的随机数组
    1、基本思路例如,我要在0~10中随机取出5个数,且这5个数不能重复,那基本思路就是:(1)在一个数组A中保存0~10的数值,然后声明一个长度为5的数组B;(2)每次在0~10的范围内随机生成一个数(3)将步骤2获取的数值作为索引获取数组A的数值,并将该值赋给数组B,同时移除数组A中的该值(4)训练5次,得到数组B......
  • pytest结合allure-pytest插件 生成allure测试报告
     注意:allure-pytest 从1.7之后已弃用,从2.0版本开始迁移至 allure-python 项目(即使用allure2),另外要运行allure命令行也需要Java的支持。1、安装allure-pytestpipinstall-U allure-pytest 这将安装allure-pytest和allure-python-commons程序包,以生成与allure2兼容的报告......
  • 在线Cron表达式生成/Linux Cron
    https://cron.qqe2.com/https://www.runoob.com/linux/linux-comm-crontab.html 022**6 ......
  • 塔猫之ChatPPT 国内一个AI自动生成PPT效率工具【使用后一点想法】
    我有个同事为了肝PPT熬夜到天明,结果第二天就生病了,抵抗力一落千丈啊! 做PPT可真是够折磨人的。我有个同事为了肝PPT熬夜到天明,结果第二天就生病了,抵抗力一落千丈啊!这种情况也真的很常见,毕竟制作一个好的演示文稿需要大量思考、设计、排版和修图等等工序,全程手动操作不仅费时费......
  • 浅析python中的生成器和迭代器
    一、什么叫生成器?在Python中,一边循环一边计算的机制,称为生成器:generator二、怎么创建生成器1.生成器表达式()生成器表达式返回一个生成器对象,需要用一个变量名来接收g=(x*3forxinrange(5))#打印g,返回一个生成器对象print(g)#<generatorobject<genexpr>at0x000......
  • 【GIT】学习day03 | 如何生成并配置SSH公钥
    快速笔记:1、注册并激活码云账号2、生成并配置SSH公钥(运行[email protected]检测SSH公钥是否配置成功)3、创建空白的码云仓库4、把本地项目上传到码云对应的空白仓库中双击进入 打开里面复制公钥 添加到gitee上即可 新建仓库步骤 然后创建就完事了,不过一开始......
  • 结对编程——随机生成四则运算程序
    在本次结对编程中,我和2152634王锴中同学一同进行参与了随机生成四则运算题目程序的编写,本次编写环境在clion上,使用c++风格的代码完成编写。在编写的过程中,我们一同探讨了用哪种语言进行编译,最终选定c++,原因在于对c++的掌握程度更深。在一起完成此项目的同时,我们收获了很多,尤其对方......
  • 小白用chatgpt编写python 爬虫程序代码 抓取网页数据(js动态生成网页元素)
    jS动态生成,由于呈现在网页上的内容是由JS生成而来,我们能够在浏览器上看得到,但是在HTML源码中却发现不了一、注意:代码加入了常规的防爬技术    如果不加,如果网站有防爬技术,比如频繁访问,后面你会发现什么数据都取不到1.1 模拟请求头: 这里入进入一步加强,随机,主要是User-Agen......