bzoj 3754 Tree之最小方差樹

2021-07-22 09:51:26 字數 1210 閱讀 7022

題目大意:給你乙個無相連通圖,要你找出乙個生成樹,使得他們的邊權的方差最小。n<=100,m<=2000,c(邊權)<=100

我們考慮最小生出樹常用的kruskal演算法,它需要得到乙個邊的排列,然後在進行貪心的加邊。我們可以考慮暴力每個排列,然後進行kruskal。這樣時間複雜度為o(m!m)。

我們發現複雜度的瓶頸就在於排列個數太多,於是考慮如何減少排列個數。

假設平均數為a,那麼對於每條邊我們可以得到乙個新的權值,然後進行排序。如果我們列舉了所有可能的平均數,那麼他們之間至少有乙個排列是最優的。時間複雜度o(mcmlogm)

還是不足以通過本題,需要繼續優化。

我們可以發現,當乙個平均數從k/(n-1)變成(k+1)/(n-1)時,雖然每條邊的邊權會改變,但是排列的順序可能不會改變。於是我們考慮何時排列順序會改變,對於任意兩條邊的順序,只有當a從小於(c1+c2)/2變成大於(c1+c2)/2時才會改變。於是我們只需要對於任意的i,j,a=(ci+cj)/2-eps,與a=(ci+cj)/2+eps,這些平均數進行kruskal即可。時間複雜度o(m^3logm)

看上去好像還不如優化前的,其實不然,因為這題的c很小,所以有許多的(ci+cj)/2會相等,對於這樣的我們只要做一次就好了。時間複雜度o(cmlogm)

然後我們發現這題是稠密圖,可以考慮用prim(實測比kruskal快),時間複雜度o(cn^2)

以下是code

#include#include#include#include#include#includeusing namespace std;

const int maxn=111,maxm=4011;

int tot=0,now[maxn],pre[maxm],son[maxm],v[maxm];

void add(int a,int b,int c)

void cc(int a,int b,int c)

int n,m,e[maxm];

void init()

double w[maxm];

double ans;

void gao(double d){

double res=0;

for (int i=2;i<=n;++i) res+=d[i];

res/=n-1; double s=0;

for (int i=2;i<=n;++i) s+=(d[i]-res)*(d[i]-res);

s=s/(n-1); if (s

BZOJ 2654 tree 二分 最小生成樹

給出一些邊,每個邊有乙個邊權和顏色。現在要求出最小邊權有need個白邊的生成樹。輸出這個邊權。在白邊上加乙個權值,這樣就可以人為的改變白邊出現在最小生成樹。這個東西顯然可以二分。之後取一下最小值就可以了。define crt secure no warnings include include in...

bzoj2654 tree 二分 最小生成樹

time limit 30 sec memory limit 512 mb submit status discuss 給你乙個無向帶權連通圖,每條邊是黑色或白色。讓你求一棵最小權的恰好有need條白色邊的生成樹。題目保證有解。第一行v,e,need分別表示點數,邊數和需要的白色邊數。接下來e行,每...

bzoj2654 二分 最小生成樹 tree

題目傳送門 description 給你乙個無向帶權連通圖,每條邊是黑色或白色。讓你求一棵最小權的恰好有need條白色邊的生成樹。題目保證有解。input 第一行v,e,need分別表示點數,邊數和需要的白色邊數。接下來e行,每行s,t,c,col表示這邊的端點 點從0開始標號 邊權,顏色 0白色1...