野餐規劃(最小度限制生成樹)

2021-10-09 06:44:44 字數 2953 閱讀 2977

一群小丑演員,以其出色的柔術表演,可以無限量的鑽進同一輛汽車中,而聞名世界。

現在他們想要去公園玩耍,但是他們的經費非常緊缺。

他們將乘車前往公園,為了減少花費,他們決定選擇一種合理的乘車方式,可以使得他們去往公園需要的所有汽車行駛的總公里數最少。

為此,他們願意通過很多人擠在同一輛車的方式,來減少汽車行駛的總花銷。

由此,他們可以很多人駕車到某乙個兄弟的家裡,然後所有人都鑽進一輛車裡,再繼續前進。

公園的停車場能停放的車的數量有限,而且因為公園有入場費,所以一旦一輛車子進入到公園內,就必須停在那裡,不能再去接其他人。

現在請你想出一種方法,可以使得他們全都到達公園的情況下,所有汽車行駛的總路程最少。

第一行包含整數n,表示人和人之間或人和公園之間的道路的總數量。

接下來n行,每行包含兩個字串a、b和乙個整數l,用以描述人a和人b之前存在道路,路長為l,或者描述某人和公園之間存在道路,路長為l。

道路都是雙向的,並且人數不超過20,表示人的名字的字串長度不超過10,公園用「park」表示。

再接下來一行,包含整數s,表示公園的最大停車數量。

你可以假設每個人的家都有一條通往公園的道路。

輸出格式

輸出「total miles driven: ***」,其中***表示所有汽車行駛的總路程。

樣例輸入

10alphonzo bernardo 32

alphonzo park 57

alphonzo eduardo 43

bernardo park 19

bernardo clemenzi 82

clemenzi park 65

clemenzi herb 90

clemenzi eduardo 109

park herb 24

herb eduardo 79

3樣例輸出

total miles driven: 183

這道題思路比較好想,但有點難打(細節巨多)。

首先題意可以轉化為:給定一張n個點,m條邊的無向圖,求出一顆最小生成樹,滿足1號節點的度數不超過給定整數s。

1.我們先將名字用map轉化為節點,用鄰接表儲存。

2.去掉1號節點,跑乙個kruskal,讓離1號節點近的當根節點,注意用vis標記哪些邊在樹上,這樣得到乙個森林,每一棵樹都為最小生成樹,共有t棵樹。

3.dfs找到每棵樹中每個點到根節點的路徑上最長邊用結構體記錄(每棵樹從根節點dfs,只找一次)。

4.接著列舉每乙個根節點,將其與1號連線(注意更新答案和vis)。

5.再考慮從每棵樹根節點出發的每條不在樹上的邊(1,x)邊權為z,運用之前找到的每條路徑上的最長邊(u,v),邊權為w。從節點2至n列舉,最小化(z,w),若(z-w)> 0,則用(1,x)替換(u,v)。記住用dfs從x開始更新,vis也要更新。

6.第五條重複s-t次或w-z<0。

#include.h>

using namespace std;

const

int m=

1e3+5;

int ans,n,cnt,tot,k;

int fa[m]

,vis[m]

[m],d[m]

[m];

struct edge

edge

(int v,

int w)

}p[m]

,t[m]

;void

makeset()

}int

findset

(int x)

return fa[x];}

void

unionset

(int u,

int v)

else

}bool cmp

(edge e1,edge e2)

void

init()

if(it2!=name.

end())

v=it2-

>second;

else

p[++cnt]

.u=u;p[cnt]

.v=v;p[cnt]

.w=w;

d[u]

[v]=w,d[v]

[u]=w;

//鄰接表

}scanf

("%d"

,&k);}

void

kruskal()

int x1=

findset

(p[i]

.u);

int x2=

findset

(p[i]

.v);

if(x1!=x2)}}

void

dfs(

int now,

int last,

int u,

int v)

else}}

}void

work()

for(

int i=

2;i<=tot;i++)}

while

(k--)if

(_ans.w-d[i][1

])}if

(_ans==0)

break

;//已最優

ans-=_ans;

vis[1]

[ex]=1

,vis[ex][1

]=1;

//刪邊,加邊

vis[t[ex]

.u][t[ex]

.v]=

0,vis[t[ex]

.v][t[ex]

.u]=0;

dfs(ex,1,

-1,-

1);//從ex開始更新最長路徑

}printf

("total miles driven: %d\n"

,ans);}

intmain()

最小度限制生成樹

最小度限制生成樹 具體講解和證明,黑書上有,ioi2004國家集訓隊 王汀 中也有講解,這裡簡單介紹求法過程。為了方便敘述,把頂點v0的度數 k稱作度限制條件,把滿足這一條件的生成樹稱為度限制生成樹,把權值和最小的度限制生成樹稱為最小度限制生成樹。要求的最小k度生成樹,應該有以下的步驟 演算法框架 ...

最小度限制生成樹

在一棵生成樹中,某個頂點v0的度數 k稱作度限制條件,把滿足這一條件的生成樹稱為度限制生成樹,把權值和最小的度限制生成樹稱為最小度限制生成樹。如果撇開度限制條件,那麼就是最小生成樹問題。首先,避開度限制條件。假如把最小度限制生成樹中所有與v0相關的邊都刪掉,得到m個連通分量。具體步驟 1.如果k 2...

最小度限制生成樹

黑書 各種資料。終於理解了一點。最小度限制生成樹就是給乙個圖,讓求它的最小生成樹。找的的最小生成樹滿足並且點vo的度最大為k。演算法流程如下 1.將該點 以下用v0表示 從圖中刪除,將得到m個連通分量。2.對每個連通分量求最小生成樹,假設m個。3.從每個連通分量中找與v0關聯的權值最小的邊,與v0相...