U120773 森林擴張

2022-02-17 14:42:49 字數 3352 閱讀 5343

原題鏈結  

不知道為什麼我們正在學習$dp$,教練卻讓我們做一套圖論題 $emmm~$

給你一棵森林,連一條邊 $( u,v )$ 的代價為 $a [ u ] + a [ v ]$,且每個點最多只能連一條邊,問將森林連成一棵樹的最小代價 。

考慮到連通塊內的點不需要再連了,所以我們可以先將原圖進行縮點;

這樣就變成了 「 有 $n$ 個點,求將其連成一棵樹的最小代價 」,最小生成樹!

考慮到我們需要連 $n-1$ 條邊,所以說從乙個連通塊連向其他連通塊的邊最多有 $n-1$ 條,所以我們可以貪心地從每個連通塊裡找前 $n-1$ 小的點,分別於剩下 $n-1$ 個集合的最小的點連邊,最後再跑一邊最小生成樹就搞定了。

當然它 $re$ 了,不然就不會有這篇部落格了$qwq$ 。

#include#include

#include

#include

#include

using

namespace

std;

const

int n=1e5+5

;int

read()

while(ch>='

0'&&ch<='9'

)

return a*x;

}int

n,m,tim,top,edge_sum,scc_sum,edge_sum,ans,tot,bj;

intval[n],head[n],dfn[n],low[n],s[n],vis[n],scc[n],minx[n],head[n],fa[n],vis[n];

vector

ve[n];

struct

node

a[n],b[n];

void add(int

from,int

to)void tarjan(int

u)

else

if(vis[v]) low[u]=min(low[u],dfn[v]);

}if(dfn[u]==low[u])

vis[u]=0

; scc[u]=scc_sum;

ve[scc_sum].push_back(u);

if(val[u]u;

top--;

}}void add(int

from,int to,int

dis)

bool

cmp(node x,node y)

int getfa(int

x)int

main()

memset(minx,

0x3f,sizeof

(minx));

for(int i=1;i<=n;i++)

if(scc_sum==1

)

for(int i=1;i<=scc_sum;i++)

}fa[i]=i;

}sort(b+1,b+1+edge_sum,cmp);

for(int i=1;i<=edge_sum;i++)

}if(bj) printf("

%d\n

",ans);

else printf("

-1\n");

return0;

}

我的**

因為這道題是無向圖,所以求連通塊的過程我們可以用並查集 。

還是順著上面的思路走,既然我們需要連 $n-1$ 條邊使得原圖變成一棵樹,也就是說我們必須要從每個連通塊裡至少找乙個點與其他連通塊連邊,貪心地來看,這個點一定是連通塊裡最小的點,即這 $n-1$ 條邊的其中一端一定是某個連通塊內最小的點,而且其中一條邊的兩端是某兩個連通塊內最小的點,否則不會是最優方案;

我們需要連 $n-1$ 條邊,則需要先找到 $2 * ( n-1 )$ 個點,現在我們已經找到了 $n$ 個點了,剩下的 $n-2$ 個點怎麼找呢?

我們只需要在剩下的所有點出找出 $n-2$ 個最小的點就好了 。

大膽猜想,無需證明。

這個貪心思路想一想就能證明是對的 。

考慮一下極端情況:剩下的 $n-2$ 個都來自於同乙個連通塊 $k$;

這種情況下就是從連通塊 $k$ 總共選了 $n-1$ 個點,再從剩下 $n-1$ 個連通塊中各找乙個最小的點與之連邊,形成乙個菊花圖的樣子,不難證明這確實是最優方案;

#includeusing

namespace

std;

const

int n=1e6+5

;int

read()

while(ch>='

0'&&ch<='9'

)

return a*x;

}int

n,m,tot;

intval[n],fa[n];

long

long

ans;

vector

long>f[n];

int getfa(int x) //

求點x的父親

intmain()

for(int i=1;i<=n;i++)

for(int i=1;i<=m;i++)

for(int i=1;i<=n;i++)

if(tot==1) //

只有乙個連通塊,說明原圖本來就是一棵樹,直接輸出0

for(int i=1;i<=n;i++) //

將每個連通塊內的點從小到大排序

sort(f[i].begin(),f[i].end());

for(int i=1;i<=n;i++) //

列舉每個連通塊

}if(f[0].size()2) //

我們還需要找tot-2個點進行連邊,如果不夠的話,肯定是無解的

sort(f[

0].begin(),f[0].end()); //

從小到大排序

for(int i=0;i2;i++) //

貪心地找出前tot-2小的點

ans+=f[0][i]; //

算答案

printf("

%lld\n

",ans); //

愉快地輸出

return0;

}

U的含義,u是什麼單位

u 是一種表示機架式伺服器外部尺寸的單位,是unit的縮略語,詳細尺寸由作為業界團體的美國電子工業協會 eia 決定。之所以要規定伺服器的尺寸,是為了使 伺服器保持適當的尺寸以便放在鐵質或鋁質機架上。機架上有固定伺服器的螺孔,將它與伺服器的螺孔對好,用螺絲加以固定。將伺服器放置到機架上,並不僅僅有利...

STM32中U8, U16 ,U32啥意思

1.unsigned int 32 c語言標準表達方法 2.uint32 t 3.u32 這三種方式都是在表達同乙個意思。可為什麼st的開發人員要搞的這麼亂呢?其實st 搞這麼多花樣,無非是想開發人員在寫 時定義資料型別能少寫幾個符號,然後又因為前後版本公升級,為了相容舊版本 主要是v2.0 才會出...

c語言中u8,u16,u32和int區別

c語言中u8,u16,u32和int區別為符號不同 資料範圍不同 記憶體占用的空間不同。一 符號不同 1 u8 u8表示無符號char字元型別。2 u16 u16表示無符號short短整數型別。3 u32 u32表示無符號int基本整數型別。4 int int表示帶符號int基本整數型別。二 資料範...