APIO2008 免費道路 克魯斯卡爾專精

2021-10-23 07:02:09 字數 1570 閱讀 9939

題面

給定一張n個點m條邊的無向圖(不保證聯通),其中圖上每個邊都有顏色(黑白),現在要構造一棵生成樹,使樹上黑邊數量等於k,如果不存在合法的構造方案,輸出"no solution"。

k

2×10

4k

k2×104m≤

10

5m \le10^5

m≤105題解

首先考慮什麼時候會no solotion

圖不連通

k太大,比黑邊總數還大

k太小,以至於只用k條黑邊無法使圖聯通

其中第一和第二種都很好判斷,至於第三種,簡單粗暴的方法是按白邊構成的聯通塊縮點,看縮完的圖的點數是否比k小(這裡預設圖是聯通的),但是這個辦法太繁瑣了,如果熟練克魯斯卡爾的話,很容易得出第二種方法。

第一遍克魯斯卡爾,處理出必須連的黑邊,即縮完點後的圖上的生成樹邊,具體實現就是先把所有能加進生成樹的白邊加進去,再來掃黑邊,這時加進去的黑邊是必須連的。

然後第二遍克魯斯卡爾,先把必須連的黑邊連進去,然後再加入黑邊,直到黑邊數量達到k,然後加白邊,這樣同時就完成了構造。

這個思考過程我寫的比較短,所以比較精髓,建議慢慢讀。

放**!

# include

using

namespace std;

namespace fastio

template

<

typename tn>

void

print

(tn a)};

using

namespace fastio;

const

int n=

2e4+5;

const

int m=

1e5+4;

int n,m,k;

struct edgee0[m]

,e1[m]

,em[m]

;int ct0,ct1,ctm,sum,tot;

int f[n]

;int

find

(int x)

intmain()

;else e0[

++ct0]

=(edge);}

for(

int i=

1;i<=n;i++

) f[i]

=i;for

(int i=

1;i<=ct0;i++

)for

(int i=

1;i<=ct1;i++)if

(sum1||ctm>k||ct1for(

int i=

1;i<=n;i++

) f[i]

=i;for

(int i=

1;i<=ctm;i++

) tot=ctm;

for(

int i=

1;tot)for

(int i=

1;i<=ct0;i++

)return0;

}

話說我時至今日,寫到這道題時才幡然大悟:原來cnt是count的意思!

APIO2008 免費道路

bzoj luogu 先把必須連的鵝卵石路連上,大於k條no solution 什麼樣的鵝卵石路 u,v 必須連?所有水泥路都連上仍然不能使u,v連通的必須連 補全到k條鵝卵石路,補不全no solution 最後用水泥路構出生成樹,構不出no solution includeusing names...

APIO2008 免費道路

kruskal 好題 0 邊的數量在某些情況下是可以無限制的調控的,前提是所有必須存在的邊都在生成樹里了 所以應該分別求出有哪些邊是必須在生成樹里的,我們可以先從大到小排序,求出有哪些 0 邊必須在生成樹里,之後再從小到大排序,求出那些 1 邊必須在生成樹里 之後剩下的邊就可以隨便放了,調控 0 邊...

APIO2008 免費道路 生成樹

新亞 new asia 王國有 n 個村莊,由 m 條道路連線。其中一些道路是鵝卵石路,而其它道路是水泥路。保持道路免費執行需要一大筆費用,並且看上去 王國不可能保持所有道路免費。為此亟待制定乙個新的道路維護計畫。國王已決定保持盡可能少的道路免費,但是兩個不同的村莊之間都應該一條且僅由一條 且僅由一...