題意:給出n個點和m條邊的無向圖,存在重邊,問加一條邊以後,剩下的橋的數量最少為多少。
題解:你把這個無向圖縮點後會得到乙個只由橋來連線的圖(可以說這個圖中的所有邊都是橋,相當於一棵樹),然後我們只需要找出來這棵樹的最大直徑(即相距最遠的兩個點)。然後我們可以把得到的這條鏈的首尾兩端連起來,因為這樣減少的橋最多。把所有橋減去這條鏈上的橋就是答案
找樹的直徑有兩種方法,一種樹形dp,一種兩次dfs演算法。時間複雜度都是o(n)
先說dfs:
實現:隨意選取乙個點作為我們的起點x,找到以x為起點的和它是最遠距離的另乙個端點y,然後再以y為起點找到和它是最遠距離的另乙個端點z,這個y->z就是樹的最大直徑
本題**1就是採用的這種解法
再說樹形dp:
缺點:無法找到它的直徑具體路徑
優點:只需一遍遍歷
實現:
1**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 #include2 #includeview code3 #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 }
**2:
1view code//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 }
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條邊的圖,存在重邊,問加一條邊以後,剩下的橋的數量最少為多...