[luogu5540]最小乘积生成树

假设给定的图为$G=(V,E)$(边用四元组$(x,y,a,b)$来描述),对于其一棵生成树$T=(V,E_{T})$,根据定义代价即为$sum_{(x,y,a,b)in E_{T}}asum_{(x,y,a,b)in E_{T}}b$

考虑构造一个二维平面,生成树$T$对应于平面上的一个点$(sum_{(x,y,a,b)in E_{T}}a,sum_{(x,y,a,b)in E_{T}}b)$,令这些点构成集合$S$,我们即求$min_{(x,y)in S}xy$

对$S$求左下凸壳,构成集合$S'$(删去$S'$中不必要的点,即不允许三点共线)

结论:$min_{(x,y)in S}xy=min_{(x,y)in S'}xy$

考虑$(x,y)in S$,选择$S'$中$x$坐标小于等于$x$且最大的点$(x_{1},y_{1})$和大于等于$x$且最小的点$(x_{2},y_{2})$,将两点连线后经过点$(x,y')$,根据凸壳的性质有$yge y'$,即$xyge xy'$

下面,考虑来证明$xy'ge min(x_{1}y_{1},x_{2}y_{2})$即可

由于$(x,y')$在两点连线上,有$y'=y_{1}+frac{y_{2}-y_{1}}{x_{2}-x_{1}}(x-x_{1})$,代入即$xy'=frac{y_{2}-y_{1}}{x_{2}-x_{1}}x^{2}+(y_{1}-frac{y_{2}-y_{1}}{x_{2}-x_{1}}x_{1})x$

注意到$frac{y_{2}-y_{1}}{x_{2}-x_{1}}<0$,又因为$x_{1}le xle x_{2}$,显然其最小值在$x=x_{1}$或$x=x_{2}$时取到,代入可得$y$恰为$y_{1}$和$y_{2}$,即其最小值为$min(x_{1}y_{1},x_{2}y_{2})$,得证

下面来求这个凸壳$S'$,考虑递归来求,具体即——

假设已经求出$(x_{1},y_{1}),(x_{2},y_{2})in S'$(不妨假设$x_{1}<x_{2}$),找到任意一点$(x_{3},y_{3})$满足$x_{1}<x_{3}<x_{2}$且$(x_{3},y_{3})in S'$,并分别递归$(x_{1},y_{1})$和$(x_{3},y_{3})$、$(x_{3},y_{3})$和$(x_{2},y_{2})$即可

简单贪心即可求出凸壳上$x$坐标最小和最大($y$坐标最小)的两点,以此为基础进行递归

下面考虑如何求$(x_{3},y_{3})$,构造$(x_{3},y_{3})$是$S$中到$(x_{1},y_{1})$和$(x_{2},y_{2})$连线上距离最远的点(这里的距离是有方向的,在其连线下方为正、上方为负),距离相同时取$x_{3}$最小

特别的,当此距离小于等于0,即不存在满足条件的$(x_{3},y_{3})$,结束即可

关于这一做法的正确性证明,只需要说明以下两点:

1.若该点到$(x_{1},y_{1})$和$(x_{2},y_{2})$连线上距离小于等于0,不存在满足条件的$(x_{3},y_{3})$

2.若该点到$(x_{1},y_{1})$和$(x_{2},y_{2})$连线上距离大于0,其满足$x_{1}<x_{3}<x_{2}$且$(x_{3},y_{3})in S'$

根据凸壳的性质,都是可以说明的

同时,最大化此距离也即最小化过$(x_{3},y_{3})$作斜率为$frac{y_{2}-y_{1}}{x_{2}-x_{1}}$的直线的截距,也即$y_{3}+frac{y_{2}-y_{1}}{x_{2}-x_{1}}x_{3}$

联系最开始的定义,以$frac{y_{2}-y_{1}}{x_{2}-x_{1}}a+b$为边权求最小生成树即可(在$frac{y_{2}-y_{1}}{x_{2}-x_{1}}a+b$相同时由于希望$x_{3}$尽量小,按$a$从小到大排序),(求最小生成树)复杂度为$o(n^{2}+m)$

由此,我们就得到了一个$o(|S'|(n^{2}+m)$的做法,来考虑$|S'|$

 

注意到$S$中的点都是整点,且范围在$[0,nV]$中(其中$V$为$a$和$b$的范围,记$N=nV$)

假设其有$k$段直线,第$i$条直线斜率为$-frac{p_{i}}{q_{i}}$(其中$p_{i},q_{i}ge 1$且$(p_{i},q_{i})=1$),即有$forall 1le i<k,frac{p_{i}}{q_{i}}>frac{p_{i+1}}{q_{i+1}}$(凸性),且需要能在$[0,N]$中放得下,即$sum_{i=1}^{k}p_{i},sum_{i=1}^{k}q_{i}le N$

对于其中$max(p_{i},q_{i})le N^{frac{1}{3}}$的位置,由于不会重复,至多有$o(N^{frac{2}{3}})$个数

对于其中$max(p_{i},q_{i})>N^{frac{1}{3}}$的位置,根据和不超过$N$的条件,也至多有$o(N^{frac{2}{3}})$个位置

综上,我们就说明了$|S'|=k+1sim o(N^{frac{2}{3}})$,总复杂度即$o(n^{frac{8}{3}}V^{frac{2}{3}}+n^{frac{2}{3}}V^{frac{2}{3}}m)$

另外顺带一提,在数据随机时,对于$n$个点的凸包期望点数为$o(log n)$,由于至多只有$o(n^{n-2})$棵生成树(点),因此$|S'|$的期望是$o(nlog n)$的,总复杂度为$o(n^{3}log n)$(虽然会被卡,其实比较困难)

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 205
 4 #define pii pair<int,int>
 5 #define fi first
 6 #define se second
 7 vector<pii >v[N][N];
 8 pii ans,d[N];
 9 int n,m,x,y,a,b,vis[N];
10 double tmp;
11 bool cmp(pii x,pii y){
12     return tmp*x.fi+x.se<tmp*y.fi+y.se;
13 }
14 void get_min(pii k){
15     if (1LL*k.fi*k.se<1LL*ans.fi*ans.se)ans=k;
16     if ((1LL*k.fi*k.se==1LL*ans.fi*ans.se)&&(k.fi<ans.fi))ans=k;
17 }
18 pii calc(double k){
19     tmp=k;
20     pii ans=make_pair(0,0);
21     memset(vis,0,sizeof(vis));
22     d[1]=make_pair(0,0);
23     for(int i=2;i<=n;i++)d[i]=make_pair(0x3f3f3f3f,0x3f3f3f3f);
24     for(int i=1;i<=n;i++){
25         int k=-1;
26         for(int j=1;j<=n;j++)
27             if ((!vis[j])&&((k<0)||(cmp(d[j],d[k]))))k=j;
28         vis[k]=1;
29         ans.fi+=d[k].fi,ans.se+=d[k].se;
30         for(int j=1;j<=n;j++)
31             for(int t=0;t<v[k][j].size();t++)
32                 if (cmp(v[k][j][t],d[j]))d[j]=v[k][j][t];
33     }
34     get_min(ans);
35     return ans;
36 }
37 void dfs(pii x,pii y){
38     if (x.fi==y.fi)return;
39     pii o=calc(1.0*(y.se-x.se)/(x.fi-y.fi));
40     if (!cmp(o,x))return;
41     dfs(x,o),dfs(o,y);
42 }
43 int main(){
44     scanf("%d%d",&n,&m);
45     for(int i=1;i<=m;i++){
46         scanf("%d%d%d%d",&x,&y,&a,&b);
47         x++,y++;
48         v[x][y].push_back(make_pair(a,b));
49         v[y][x].push_back(make_pair(a,b));
50     }
51     ans.fi=ans.se=1e5;
52     dfs(calc(1e5),calc(0));
53     printf("%d %d",ans.fi,ans.se);
54 } 
View Code
原文地址:https://www.cnblogs.com/PYWBKTDA/p/14627951.html