LuoguP5540:【模板】最小乘积生成树(几何逼近)

题意:给定N点,M边,每条边有两个属性(a,b),现在让你选N-1条边出来,然后使得∑a*∑b最小。N<200,M<1e4;

思路:我们把∑a看成x,∑b看成y,那么一个方案对应一个二维坐标(x,y)。假设我知道了其中两个方案[A,B],那么,如果另外一个方案C更优,则在二维平面上,C至少要满足在A和B的左边。然后[A,C],[C,B]继续下推。 这个有点像凸包的逼近,所以复杂度和凸包上的点数有关,其理论点数是sqrt(lnN)的。所以总的复杂度趋近于NlogN*sqrt(lnN);

#include<bits/stdc++.h>
#define ll long long
#define pii pair<ll,ll>
#define f first
#define ss second
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=2000010;
struct in{
    int u,v;ll a,b,C;
}s[maxn];
bool cmp(in p,in q){ return p.C<q.C;}
int fa[maxn],N,M; ll ans=1LL<<60; pii fcy;
int find(int x){
    if(x==fa[x]) return x;
    return fa[x]=find(fa[x]);
}
pii solve()
{
    pii res=make_pair(0,0);
    rep(i,1,N) fa[i]=i;
    sort(s+1,s+M+1,cmp);
    rep(i,1,M) {
        if(find(s[i].u)==find(s[i].v)) continue;
        fa[find(s[i].u)]=find(s[i].v);
        res.f+=s[i].a;
        res.ss+=s[i].b;
    }
    if(res.f*res.ss<ans||(res.f*res.ss==ans&&res.f<fcy.f)) ans=res.f*res.ss,fcy=res;
    return res;
}
void MinMul(pii A,pii B)
{
    pii C;
    rep(i,1,M) s[i].C=(B.f-A.f)*s[i].b+(A.ss-B.ss)*s[i].a;
    C=solve();
    if(1LL*(B.f-A.f)*(C.ss-A.ss)-1LL*(B.ss-A.ss)*(C.f-A.f)>=0) return ;
    MinMul(A,C);
    MinMul(C,B);
}
int main()
{
    pii A,B;
    scanf("%d%d",&N,&M);
    rep(i,1,M) {
        scanf("%d%d%lld%lld",&s[i].u,&s[i].v,&s[i].a,&s[i].b);
        s[i].u++; s[i].v++;
    }
    rep(i,1,M) s[i].C=s[i].a;
    A=solve();
    rep(i,1,M) s[i].C=s[i].b;
    B=solve();
    MinMul(A,B);
    printf("%lld %lld\n",fcy.f,fcy.ss);
    return 0;
}

原文地址:https://www.cnblogs.com/hua-dong/p/11601683.html

时间: 2024-08-29 19:53:57

LuoguP5540:【模板】最小乘积生成树(几何逼近)的相关文章

HDU5697 刷题计划 dp+最小乘积生成树

分析:就是不断递归寻找靠近边界的最优解 学习博客(必须先看这个): 1:http://www.cnblogs.com/autsky-jadek/p/3959446.html 2:http://blog.csdn.net/u013849646/article/details/51524748 注:这里用的最小乘积生成树的思想,和dp结合 每次找满足条件的最优的点,只不过BZOJ裸题的满足条件是形成一棵树 这个题是大于m,生成树借用最小生成树进行求解最优,大于m用dp进行求解最优 #include

bzoj2395[Balkan 2011]Timeismoney最小乘积生成树

所谓最小乘积生成树,即对于一个无向连通图的每一条边均有两个权值xi,yi,在图中找一颗生成树,使得Σxi*Σyi取最小值. 直接处理问题较为棘手,但每条边的权值可以描述为一个二元组(xi,yi),这也就不难想到将生成树转化为平面内的点,x代表Σxi,y代表Σyi(注意这里的xi,yi指的是在生成树中的边的权值),那么问题就变成了在平面内找一个点使得x*y最小,那么显然这个点是在下凸壳上的. 因此可以首先找出两个一定在凸包上的点,例如A(minx,y),B(miny,x),在直线AB下方找一个在凸

【BZOJ2395】【Balkan 2011】Timeismoney 最小乘积生成树

链接: #include <stdio.h> int main() { puts("转载请注明出处[辗转山河弋流歌 by 空灰冰魂]谢谢"); puts("网址:blog.csdn.net/vmurder/article/details/46828379"); } 题解: 裸最小乘积生成树. 最小乘积生成树定义: 有一张n个点m条边的无向图,每条边有k个权值. 现在要取一个边集M使得其将所有点连通,并使 ∏ki=1(∑j∈Mjcost(j,vali))

二维最小乘积生成树学习小记

Preface 对于形如给定一些边,其边权为xi和yi,构造一个生成树,使得 我们称这棵树,为最小乘积生成树.我们可以考虑,沿用最小生成树的思想,把这种新颖的最小生成树做对. Content 算法简介 其实就是利用树形结合的思想,将点弄到平面直角坐标系上,使之明了,转化问题,求出最优解. 算法应用 应对类似的裸题,直接裸奔 算法核心 我们将sigma(xi)看成横坐标,sigma(yi)看成纵坐标,在坐标系中绘制出来.并在x,y轴作垂线,构成一个正方形 我们要求一种方案xy=k最小,也就是这个正

【最小乘积生成树】bzoj2395[Balkan 2011]Timeismoney

设每个点有x,y两个权值,求一棵生成树,使得sigma(x[i])*sigma(y[i])最小. 设每棵生成树为坐标系上的一个点,sigma(x[i])为横坐标,sigma(y[i])为纵坐标.则问题转化为求一个点,使得xy=k最小.即,使过这个点的反比例函数y=k/x最接近坐标轴. Step1:求得分别距x轴和y轴最近的生成树(点):A.B(分别按x权值和y权值做最小生成树即可). Step2:寻找一个在AB的靠近原点一侧的且离AB最远的生成树C,试图更新答案. [怎么找???? ——由于C离

树(最小乘积生成树,克鲁斯卡尔算法):BOI timeismoney

The NetLine company wants to offer broadband internet to N towns. For this, it suffices to constructa network of N-1 broadband links between the towns, with the property that a message can travelfrom any town to any other town on this network. NetLin

bzoj3571: [Hnoi2014]画框 最小乘积匹配+最小乘积XX总结,

思路大概同bzoj2395(传送门:http://www.cnblogs.com/DUXT/p/5739864.html),还是将每一种匹配方案的Σai看成x,Σbi看成y,然后将每种方案转化为平面上的点,再用km去找最远的点就行了. 然而几个月前就学过km且到现在还未写过一道km的题的我并不知道km如何对于负权给出最优解.... #define XX 某传统算法(例如:最小生成树,二分图最优带权匹配什么的) 顺便总结一下最小乘积XX 即对于XX引入两个权值的概念(或是多个权值,一般是两个),看

POJ 1861 ——Network——————【最小瓶颈生成树】

Network Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 15268   Accepted: 5987   Special Judge Description Andrew is working as system administrator and is planning to establish a new network in his company. There will be N hubs in the c

BZOJ2180: 最小直径生成树

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2180 2180: 最小直径生成树 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 195  Solved: 93[Submit][Status][Discuss] Description 输入一个无向图G=(V,E),W(a,b)表示边(a,b)之间的长度,求一棵生成树T,使得T的直径最小.树的直径即树的最长链,即树上距离最远的两点之间路径