題目大意:給你乙個無相連通圖,要你找出乙個生成樹,使得他們的邊權的方差最小。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...