bzoj2395[Balkan 2011]Timeismoney最小乘積生成樹

来源:http://www.cnblogs.com/DUXT/archive/2016/08/05/5739864.html
-Advertisement-
Play Games

所謂最小乘積生成樹,即對於一個無向連通圖的每一條邊均有兩個權值xi,yi,在圖中找一顆生成樹,使得Σxi*Σyi取最小值。 直接處理問題較為棘手,但每條邊的權值可以描述為一個二元組(xi,yi),這也就不難想到將生成樹轉化為平面內的點,x代表Σxi,y代表Σyi(註意這裡的xi,yi指的是在生成樹中 ...


所謂最小乘積生成樹,即對於一個無向連通圖的每一條邊均有兩個權值xi,yi,在圖中找一顆生成樹,使得Σxi*Σyi取最小值。

直接處理問題較為棘手,但每條邊的權值可以描述為一個二元組(xi,yi),這也就不難想到將生成樹轉化為平面內的點,x代表Σxi,y代表Σyi(註意這裡的xi,yi指的是在生成樹中的邊的權值),那麼問題就變成了在平面內找一個點使得x*y最小,那麼顯然這個點是在下凸殼上的。

因此可以首先找出兩個一定在凸包上的點,例如A(minx,y),B(miny,x),在直線AB下方找一個在凸包上且x*y最小的點。

於是可以每次找距離直線AB最遠的點,有兩種求法,令找到的那個點為C,如果利用叉乘,即使向量CB叉乘向量CA最大,因為我們考慮的是向量的模長,可以讓向量CA叉乘向量CB(雖然模長是負的,但並沒有什麼關係,當然也可以最大化這個值,只不過一個是最小生成樹,一個是最大生成樹而已),然後最小化這個值即可。

2S=(B.x-A.x)(C.y-B.y)-(B.y-A.y)(C.x-A.x)省略常數後就變成了B.x*C.y-A.x*C.y-B.y*C.x+A.y*C.x。

因為只需要求Σxi,Σyi,因此只需要求出點的坐標,並不要考慮面積,所以將每條邊的yi=yi*(B.x-A.x),xi=xi*(A.y-B.y),以(xi+yi)為關鍵字排序kruskal()就行了。

然後遞歸處理,直到叉積大於等於0退出(此時AB下方一定沒有點)

也可以利用點到直線的距離公式|Ax0+By0+C|/(√(A2+B2)),省略常數且保證B<=0,那麼若點在直線下方,則Ax+By+C>0。

因此可以省略絕對值符號,再省略常數,即使Ax0+By0最大,因此xi=xi*A,yi=yi*B,將(xi+yi)為關鍵字排序作最大生成樹即可,還是按叉積判斷(理應也可以看C.x*A+C.y*B<=0就退出,然而狂WA不止。。。。並不知道這是為什麼。。。。)

然後這是一道裸題,就可以愉快地切掉了。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<cmath>
 6 using namespace std;
 7 #define maxn 10100
 8 #define inf 0x7fffffff
 9  
10 int n,m;
11 int val[2*maxn],fa[maxn];
12  
13 struct edge{
14     int from,to,x,y;
15     long long z;
16 }e[maxn];
17  
18 struct node{
19     int x,y;
20     long long calc(){return (long long)x*y;}
21 }minx,miny,ans;
22  
23 int find(int x){
24     return fa[x]==x?x:fa[x]=find(fa[x]);
25 }
26  
27 node kruskal(){
28     int tot=0;node now={0,0};
29     for (int i=1;i<=n;i++) fa[i]=i;
30     for (int i=1;i<=m;i++){
31         int a=find(e[i].from),b=find(e[i].to);
32         if (a!=b){
33             fa[a]=b;
34             tot++;
35             now.x+=e[i].x;
36             now.y+=e[i].y;
37             if (tot==n-1) break;
38         }
39     }
40     long long tmpa=ans.calc(),tmpb=now.calc();
41     if (tmpb<tmpa||(tmpb==tmpa&&now.x<ans.x)) ans=now;
42     return now;
43 }
44  
45 long long cross(node a,node b,node c){
46     long long x1=(b.x-a.x),x2=(b.y-a.y),y1=(c.x-a.x),y2=(c.y-a.y);
47     return (x1*y2-x2*y1);
48 }
49  
50 bool cmpx(edge a,edge b){return a.x<b.x;}
51 bool cmpy(edge a,edge b){return a.y<b.y;}
52 bool cmpz(edge a,edge b){return a.z<b.z;}
53  
54 void solve(node a,node b){
55     for (int i=1;i<=m;i++)
56         e[i].z=e[i].y*(b.x-a.x)+e[i].x*(a.y-b.y);
57     sort(e+1,e+m+1,cmpz);
58     node t=kruskal();
59     if (cross(a,b,t)>=0) return;
60     solve(a,t);
61     solve(t,b);
62 }
63  
64 int main(){
65     scanf("%d%d",&n,&m);
66     ans=(node){inf,inf};
67     for (int i=1,u,v;i<=m;i++) scanf("%d%d%d%d",&u,&v,&e[i].x,&e[i].y),e[i].from=++u,e[i].to=++v;
68     sort(e+1,e+m+1,cmpx);
69     minx=kruskal();
70     sort(e+1,e+m+1,cmpy);
71     miny=kruskal();
72     //cout<<minx.x<<' '<<minx.y<<' '<<miny.x<<' '<<miny.y<<endl;
73     solve(minx,miny);
74     printf("%d %d",ans.x,ans.y);
75     return 0;
76 }
View Code1
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<cmath>
 6 using namespace std;
 7 #define maxn 10100
 8 #define inf 0x7fffffff
 9  
10 int n,m;
11 int val[2*maxn],fa[maxn];
12  
13 struct edge{
14     int from,to,x,y;
15     long long z;
16 }e[maxn];
17  
18 struct node{
19     int x,y;
20     long long calc(){return (long long)x*y;}
21 }minx,miny,ans;
22  
23 int find(int x){
24     return fa[x]==x?x:fa[x]=find(fa[x]);
25 }
26  
27 node kruskal(){
28     int tot=0;node now={0,0};
29     for (int i=1;i<=n;i++) fa[i]=i;
30     for (int i=1;i<=m;i++){
31         int a=find(e[i].from),b=find(e[i].to);
32         if (a!=b){
33             fa[a]=b;
34             tot++;
35             now.x+=e[i].x;
36             now.y+=e[i].y;
37             if (tot==n-1) break;
38         }
39     }
40     long long tmpa=ans.calc(),tmpb=now.calc();
41     if (tmpb<tmpa||(tmpb==tmpa&&now.x<ans.x)) ans=now;
42     return now;
43 }
44  
45 int cross(node a,node b,node c){
46     int x1=b.x-a.x,y1=b.y-a.y,x2=c.x-a.x,y2=c.y-a.y;
47     return (x1*y2-x2*y1);
48 }
49  
50 bool cmpx(edge a,edge b){return a.x<b.x;}
51 bool cmpy(edge a,edge b){return a.y<b.y;}
52 bool cmpz(edge a,edge b){return a.z>b.z;}
53  
54 void solve(node a,node b){
55     int A=b.y-a.y,B=a.x-b.x;
56     for (int i=1;i<=m;i++) e[i].z=e[i].x*A+e[i].y*B;
57     sort(e+1,e+m+1,cmpz);
58     node t=kruskal();
59     if (cross(a,b,t)<0) solve(a,t),solve(t,b);
60 }
61  
62 int main(){
63 //  freopen("data.in","r",stdin);
64 //  freopen("WA.out","w",stdout);
65     scanf("%d%d",&n,&m);
66     ans=(node){inf,inf};
67     for (int i=1,u,v;i<=m;i++) scanf("%d%d%d%d",&u,&v,&e[i].x,&e[i].y),e[i].from=++u,e[i].to=++v;
68     sort(e+1,e+m+1,cmpx);
69     minx=kruskal();
70     sort(e+1,e+m+1,cmpy);
71     miny=kruskal();
72     //cout<<minx.x<<' '<<minx.y<<' '<<miny.x<<' '<<miny.y<<endl;
73     solve(minx,miny);
74     printf("%d %d",ans.x,ans.y);
75     return 0;
76 }
View Code2
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • .NET Core中間件的註冊和管道的構建(1) 註冊和構建原理 0x00 問題的產生 管道是.NET Core中非常關鍵的一個概念,很多重要的組件都以中間件的形式存在,包括許可權管理、會話管理、路由等。所以搞明白中間件是如何註冊並最終構建成管道的很重要。園子里很多先驅早已經開始了這方面的研究學習,也 ...
  • winform: webform: https://github.com/asposemarketplace/Aspose_for_OpenXML ...
  • public void Out(out int a, out int b) {//out相當於return返回值 //可以返回多個值 //拿過來變數名的時候,裡面預設為空值 a=1; b=2; } static void Main(string[] args) { int a = 0; int b ...
  • ASPX 優點: 通過上面小小的對比,不難看出,與ASP.NET MVC緊密集成,對於以往ASP.NET開發人員有更好體驗。其實它還有其他幾優點: ●智能感應 ●能選擇其它語言的 CodeDom provider (例如: C#, VB.NET, F#, Boo, Nemerle) ●立即編譯或預編 ...
  • ...
  • 物理文件是我們最常用到的原始配置的載體,最佳的配置文件格式主要由三種,它們分別是JSON、XML和INI,對應的配置源類型分別是JsonConfigurationSource、XmlConfigurationSource和IniConfigurationSource。 ...
  • 為什麼不直接使用<img src="{{phone.imageUrl}}">因為瀏覽器會請求{{phone.imageUrl}}這個url。 ...
  • 1、基本思想:設無向連通網為G=(V, E),令G的最小生成樹為T=(U, TE),其初態為U=V,TE={ },然後,按照邊的權值由小到大的順序,考察G的邊集E中的各條邊。若被考察的邊的兩個頂點屬於T的兩個不同的連通分量,則將此邊作為最小生成樹的邊加入到T中,同時把兩個連通分量連接為一個連通分量; ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...