日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

P5540-[BalkanOI2011]timeismoney|最小乘积生成树【最小生成树,凸壳】

發(fā)布時(shí)間:2023/12/3 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 P5540-[BalkanOI2011]timeismoney|最小乘积生成树【最小生成树,凸壳】 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

正題

題目鏈接:https://www.luogu.com.cn/problem/P5540


題目大意

給出nnn個(gè)點(diǎn)mmm條邊邊權(quán)是一個(gè)二元組(ai,bi)(a_i,b_i)(ai?,bi?),求出一棵生成樹最小化
(∑e∈Tae)×(∑e∈Tbe)(\sum_{e\in T}a_e)\times(\sum_{e\in T}b_e)(eT?ae?)×(eT?be?)
的情況下最小化∑e∈Tae\sum_{e\in T}a_eeT?ae?

1≤n≤200,1≤m≤1041\leq n\leq 200,1\leq m\leq 10^41n200,1m104


解題思路

這種帶乘積的可以維護(hù)凸殼,對(duì)于一棵生成樹TTT我們視為一個(gè)(∑e∈Tae,∑e∈Tbi)(\sum_{e\in T}a_e,\sum_{e\in T}b_i)(eT?ae?,eT?bi?)的點(diǎn),這樣我們打答案一定在下凸殼上。

可以用一種分治求凸殼的方法,我們先找出下凸殼的兩個(gè)端點(diǎn)(xxx最小的和yyy最小的)記為A,BA,BA,B,然后找到一個(gè)在AAABBB的連邊下面的一個(gè)最凸的點(diǎn)CCC(可以視為最大化S△ACBS_{\bigtriangleup ACB}SACB?,這樣CCC一定在凸殼上),然后分治下去做AC?\vec{AC}ACCB?\vec{CB}CB

考慮怎么求這個(gè)CCC,就是最大化AC?×CB?\vec{AC}\times \vec{CB}AC×CB
(xC?xA)(yB?yA)?(xB?xA)(yC?yA)(x_C-x_A)(y_B-y_A)-(x_B-x_A)(y_C-y_A)(xC??xA?)(yB??yA?)?(xB??xA?)(yC??yA?)
=xC(yB?yA)?yC(xB?xA)+yA(xB?xA)?xA(yB?yA)=x_C(y_B-y_A)-y_C(x_B-x_A)+y_A(x_B-x_A)-x_A(y_B-y_A)=xC?(yB??yA?)?yC?(xB??xA?)+yA?(xB??xA?)?xA?(yB??yA?)
然后就是相當(dāng)于最小化xC(yB?yA)+yC(xA?xB)x_C(y_B-y_A)+y_C(x_A-x_B)xC?(yB??yA?)+yC?(xA??xB?),拿這個(gè)當(dāng)邊權(quán)跑就可以跑出CCC了。

然后時(shí)間復(fù)雜度據(jù)說(shuō)是O(mlog?mln?n!)O(m\log m\sqrt{\ln n!})O(mlogmlnn!?)


code

#include<cstdio> #include<cstring> #include<algorithm> #define ll long long using namespace std; const int N=210,M=1e4+10; struct node{ll x,y,w,id; }e[M]; struct point{ll x,y;point(ll xx=0,ll yy=0){x=xx;y=yy;return;} }ans; ll n,m,x[M],y[M],a[M],b[M],fa[N]; point operator-(point x,point y) {return point(x.x-y.x,x.y-y.y);} ll operator*(point x,point y) {return x.x*y.y-x.y*y.x;} bool cmp(node x,node y) {return (x.w==y.w)?(a[x.id]<a[y.id]):(x.w<y.w);} ll find(ll x) {return (fa[x]==x)?x:(fa[x]=find(fa[x]));} point Kruskal(){ll cnt=0;point res=0;for(ll i=1;i<=n;i++)fa[i]=i;sort(e+1,e+1+m,cmp);for(ll i=1;i<=m;i++){ll x=find(e[i].x),y=find(e[i].y);if(x==y)continue;fa[x]=y;cnt++;res.x+=a[e[i].id];res.y+=b[e[i].id];if(cnt==n-1)break;}if(res.x*res.y<ans.x*ans.y)ans=res;else if(res.x*res.y==ans.x*ans.y&&res.x<ans.x)ans=res;return res; } void solve(point A,point B){for(ll i=1;i<=m;i++)e[i]=(node){x[i],y[i],(B.x-A.x)*b[i]+(A.y-B.y)*a[i],i};point C=Kruskal();if((C-A)*(B-A)<=0)return;solve(A,C);solve(C,B); } signed main() {scanf("%lld%lld",&n,&m);for(ll i=1;i<=m;i++){scanf("%lld%lld%lld%lld",&x[i],&y[i],&a[i],&b[i]);x[i]++;y[i]++;}ans.x=ans.y=1e9;for(ll i=1;i<=m;i++)e[i]=(node){x[i],y[i],a[i],i};point A=Kruskal();for(ll i=1;i<=m;i++)e[i]=(node){x[i],y[i],b[i],i};point B=Kruskal();solve(A,B);printf("%lld %lld\n",ans.x,ans.y);return 0; }

總結(jié)

以上是生活随笔為你收集整理的P5540-[BalkanOI2011]timeismoney|最小乘积生成树【最小生成树,凸壳】的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。