Warm up HDU 4612 樹的直徑

2022-06-28 09:09:08 字數 4045 閱讀 4563

題意:給出n個點和m條邊的無向圖,存在重邊,問加一條邊以後,剩下的橋的數量最少為多少。

題解:你把這個無向圖縮點後會得到乙個只由橋來連線的圖(可以說這個圖中的所有邊都是橋,相當於一棵樹),然後我們只需要找出來這棵樹的最大直徑(即相距最遠的兩個點)。然後我們可以把得到的這條鏈的首尾兩端連起來,因為這樣減少的橋最多。把所有橋減去這條鏈上的橋就是答案

找樹的直徑有兩種方法,一種樹形dp,一種兩次dfs演算法。時間複雜度都是o(n)

先說dfs:

實現:隨意選取乙個點作為我們的起點x,找到以x為起點的和它是最遠距離的另乙個端點y,然後再以y為起點找到和它是最遠距離的另乙個端點z,這個y->z就是樹的最大直徑

本題**1就是採用的這種解法

再說樹形dp:

缺點:無法找到它的直徑具體路徑

優點:只需一遍遍歷

實現:

1

//選取任意結點為根遍歷樹,設dis[i]:表示結點i為根的子樹結點最遠距離。2//

則有:3

//u為根的子樹結點最遠距離dis[u]=max(dis[u],dis[u]+w(u-v)) v是u的子節點4//

最後直徑即為根結點的兩個最遠距離之和

5int dis[maxn],len=0;6

void dp(int u,int

pre)

718 }

**1:

1 #include2 #include

3 #include4 #include5 #include6 #include7

using

namespace

std;

8const

int maxn=200005

;9 vectorw[maxn];

10int head[maxn],cnt,num,stacks[maxn],top,cut,in[maxn],out

[maxn],pos,ci;

11struct

edge

12 e[2000005

];15

intvisit[maxn],belong[maxn],dfn[maxn],low[maxn];

16void add_edge(int x,int

y)17

22void

init()

2330

void tarjan(int x,int

pre)

3144

if(!dfn[v])

4549

else

if(visit[v])

5053}54

if(low[x]==dfn[x])

5567}68

}69void dfs(int x,int

t)70

76 visit[x]=1;77

int len=w[x].size();

78for(int i=0;ii)

7984}85

intmain()

8698 tarjan(1,-1

);99

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

100w[i].clear();

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

102113

}114

}115 memset(visit,0,sizeof

(visit));

116 dfs(1,0

);117 memset(visit,0,sizeof

(visit));

118 ci=0

;119 dfs(pos,0

);120 printf("

%d\n

",cut-ci-1

);121

}122

return0;

123 }

view code

**2:

1

//time 1031ms23

//memory 31340k45

#pragma comment(linker, "/stack:1024000000,1024000000")

67 #include 8

9 #include 10

11 #include 12

13 #include 14

15#define maxn 300015

1617

#define maxm 4000015

1819

using

namespace

std;

2021

struct

edgee[maxm],edge2[maxm];

2627

inthead[maxn],en;

2829

inthead2[maxn],en2;

3031

intbelong[maxn],dfn[maxn],low[maxn],stacks[maxn],top,num,scc;

3233

intn,m;

3435

bool

vis[maxn];

3637

void

init()

3839

5253

void addedge(int u,int

v)54

5564

65void addedge2(int u,int

v)66

6776

77//

void tarjan(int u,int fa)

//這個tarjan演算法也是可以用的

78//

79//

102//

103//

else if (fa==v)

104//

105//

112//

113//

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

114//

115//

}116

//117

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

118//

119//

while(x!=u);

134//

135//

}136

//137//}

138void tarjan(int x,int

pre)

139152

if(!dfn[v])

153157

else

if(vis[v])

158161

}162

if(low[x]==dfn[x])

163175

}176

}177

void

build()

178179

200201

}202

203}

204205

intans;

206207

int dfs(int u,int

p)208

209228

229 ans=max(ans,max1+max2);

230231

return

max1;

232233

}234

235int

main()

236237

266267

268269 tarjan(1,-1

);270

271build();

272273 ans=0

;274

275 dfs(1,-1

);276

277 printf("

%d\n

",scc-ans-1

);278

279}

280281

return0;

282283 }

view code

hdu4612 縮點 樹的直徑

題目大意 求乙個連通圖然後加一條邊使得橋的數目最少 題解思路 先把橋兩邊不是的點所有連通的點都縮成乙個點 然後把縮完的點構成一顆樹那麼再直徑的兩端加一條邊就是最優方案 注意 判斷重邊 題目鏈結 include include include include include include inclu...

HDU 4612 雙聯通分量 樹的直徑

點選開啟鏈結 題意 給乙個無向聯通圖,裡面可能有重邊,問新增一條邊後,使得圖中的橋最小,將橋的數量輸出 思路 剛剛讀完題,就有了思路去寫,無非就是將聯通圖雙聯通分量後縮點,然後求一條最長的路,首尾相連,肯定將更多的橋包含使得這些橋不再是橋,很好想的題,但是錯了20 什麼鬼,md重邊這麼難處理,醉了 ...

HDU4612 Tarjan縮點 BFS求樹的直徑

tarjan 縮點 樹的直徑 題意 給出n個點和m條邊的圖,存在重邊,問加一條邊以後,剩下的橋的數量最少為多少。先tarjan縮點,再在這棵樹上求直徑。加的邊即是連線這條直徑的兩端。1 2 tarjan 縮點 樹的直徑 3題意 給出n個點和m條邊的圖,存在重邊,問加一條邊以後,剩下的橋的數量最少為多...