Luogu5540 最小乘積生成樹

2022-05-25 14:24:09 字數 1446 閱讀 5264

題目描述:對於乙個\(n\)個點\(m\)條邊的無向連通圖,每條邊有兩個邊權\(a_i,b_i\),求使\((\sum a_i)\times (\sum b_i)\)最小的生成樹。

資料範圍:\(n\le 200,m\le 10000,a_i,b_i\le 255\)

這題是一道非常妙的計算幾何題目。

我們對於每個生成樹,用\((\sum a_i,\sum b_i)\)這個二維平面上的點來表示它,那麼就是求所有點中橫座標乘縱座標的最小值。

畫畫圖就可以發現,答案只有可能在下凸包上,為什麼呢?

但是生成樹可能有很多個,怎麼得到下凸包上的點呢?

為什麼呢?因為\(a,b\)兩個點必定在下凸包上面。令\(w_i=a_i\)或\(b_i\)用最小生成樹求\(a,b\)。

為什麼呢?因為\(c\)點必定在下凸包上面,否則它不是最大的點。我們發現

\[\begin

-\fracs_&=\overrightarrow\times \overrightarrow \\

&=(x_b-x_a)(y_c-y_a)-(y_b-y_a)(x_c-x_a) \\

&=((x_a-x_b)y_a-(y_a-y_b)x_a)+(x_b-x_a)y_c-(y_b-y_a)x_c

\end

\]令\(w_i=(x_b-x_a)b_i-(y_b-y_a)a_i\)就會得到\(c\)

這樣就可以求出下凸包上所有的點。那什麼時候終止遞迴呢?當然就是\(c\)不存在,或者說求出的\(c\)在\(ab\)上方。

時間複雜度為\(o(km\log m)\),其中\(k\)為下凸包上點的個數,在隨機資料下不會很大。

#include#define rint register int

using namespace std;

typedef long long ll;

const int n = 10003;

int n, m, a[n], b[n], fa[n];

struct point

inline point operator - (const point &o) const ;}

} a, b, ans(1e9, 1e9);

inline ll cross(point a, point b)

struct edge

} e[n];

inline int getfa(int x)

inline point kruskal()

} ll ans = (ll) ans.x * ans.y, res = (ll) res.x * res.y;

if(ans > res || ans == res && ans.x > res.x) ans = res;

return res;

}inline void solve(point a, point b)

int main()

最小乘積 基本型

資源限制 時間限制 1.0s 記憶體限制 512.0mb 問題描述 給兩組數,各n個。請調整每組數的排列順序,使得兩組資料相同下標元素對應相乘,然後相加的和最小。要求程式輸出這個最小值。例如兩組數分別為 1 3 5和 2 4 1 那麼對應乘積取和的最小值應為 5 4 3 2 1 1 25 輸入格式 ...

最小乘積 基本型

給兩組數,各n個。請調整每組數的排列順序,使得兩組資料相同下標元素對應相乘,然後相加的和最小。要求程式輸出這個最小值。例如兩組數分別為 1 3 5和 2 4 1 那麼對應乘積取和的最小值應為 5 4 3 2 1 1 25 第乙個行乙個數t表示資料組數。後面每組資料,先讀入乙個n,接下來兩行每行n個數...

演算法訓練53 最小乘積

問題描述 給兩組數,各n個。請調整每組數的排列順序,使得兩組資料相同下標元素對應相乘,然後相加的和最小。要求程式輸出這個最小值。例如兩組數分別為 1 3 5和 2 4 1 那麼對應乘積取和的最小值應為 5 4 3 2 1 1 25 輸入格式 第乙個行乙個數t表示資料組數。後面每組資料,先讀入乙個n,...