Your friend is developing a computer game. He has already decided how the game world should look like — it should consist of nn locations connected by mm two-way passages. The passages are designed in such a way that it should be possible to get from any location to any other location.
Of course, some passages should be guarded by the monsters (if you just can go everywhere without any difficulties, then it's not fun, right?). Some crucial passages will be guarded by really fearsome monsters, requiring the hero to prepare for battle and designing his own tactics of defeating them (commonly these kinds of monsters are called bosses). And your friend wants you to help him place these bosses.
The game will start in location ss and end in location tt, but these locations are not chosen yet. After choosing these locations, your friend will place a boss in each passage such that it is impossible to get from ss to tt without using this passage. Your friend wants to place as much bosses as possible (because more challenges means more fun, right?), so he asks you to help him determine the maximum possible number of bosses, considering that any location can be chosen as ss or as tt.
Input
The first line contains two integers nn and mm (2≤n≤3⋅1052≤n≤3⋅105, n−1≤m≤3⋅105n−1≤m≤3⋅105) — the number of locations and passages, respectively.
Then mm lines follow, each containing two integers xx and yy (1≤x,y≤n1≤x,y≤n, x≠yx≠y) describing the endpoints of one of the passages.
It is guaranteed that there is no pair of locations directly connected by two or more passages, and that any location is reachable from any other location.
Output
Print one integer — the maximum number of bosses your friend can place, considering all possible choices for ss and tt.
Examples
5 5
1 2
2 3
3 1
4 1
5 2
2
4 3
1 2
4 3
3 2
3
題意:一條路徑上必經的邊為關鍵邊,現在讓你找一條路徑,使得其關鍵邊最多,輸出最多的數量。
思路:如果一條路徑上面有環,那么這個環的任意一條邊都不是關鍵邊。所以我們縮點,那么就算在一棵樹上找最多的關鍵邊,顯然就算求直徑。
#include<bits/stdc++.h> #define ll long long using namespace std; const int maxn=600010; int From[maxn],Laxt[maxn],To[maxn<<2],Next[maxn<<2],cnt; int low[maxn],dfn[maxn],times,q[maxn],head,scc_cnt,scc[maxn]; vector<int>G[maxn]; int dis[maxn],S,T,ans; void add(int u,int v) { Next[++cnt]=Laxt[u]; From[cnt]=u; Laxt[u]=cnt; To[cnt]=v; } void tarjan(int u,int fa) { dfn[u]=low[u]=++times; q[++head]=u; for(int i=Laxt[u];i;i=Next[i]){ if(To[i]==fa) continue; if(!dfn[To[i]]) { tarjan(To[i],u); low[u]=min(low[u],low[To[i]]); } else low[u]=min(low[u],dfn[To[i]]); } if(low[u]==dfn[u]){ scc_cnt++; while(true){ int x=q[head--]; scc[x]=scc_cnt; if(x==u) break; } } } void dfs(int u,int f) { dis[u]=dis[f]+1; for(int i=0;i<G[u].size();i++){ if(G[u][i]!=f) dfs(G[u][i],u); } } int main() { int N,M,u,v,i,j; scanf("%d%d",&N,&M); for(i=1;i<=M;i++){ scanf("%d%d",&u,&v); add(u,v); add(v,u); } tarjan(1,0); for(i=1;i<=N;i++){ for(j=Laxt[i];j;j=Next[j]){ if(scc[i]!=scc[To[j]]) G[scc[i]].push_back(scc[To[j]]); } } dfs(1,0); for(i=1;i<=scc_cnt;i++) if(dis[i]>dis[S]) S=i; dfs(S,0); for(i=1;i<=scc_cnt;i++) ans=max(ans,dis[i]-1); printf("%d\n",ans); return 0; }
對於無向圖的縮點:
void tarjan(int u,int fa) { dfn[u]=low[u]=++times; q[++head]=u; for(int i=Laxt[u];i;i=Next[i]){ if(To[i]==fa) continue; if(!dfn[To[i]]) { tarjan(To[i],u); low[u]=min(low[u],low[To[i]]); } else low[u]=min(low[u],dfn[To[i]]); } if(low[u]==dfn[u]){ scc_cnt++; while(true){ int x=q[head--]; scc[x]=scc_cnt; if(x==u) break; } } }
對於有向圖的縮點:二者唯一的區別就算有向圖考慮橫邊,所以有個instack的判斷。
void tarjan(int u) { instk[u]=1; q[++head]=u; dfn[u]=low[u]=++times; for(int i=Laxt[u];i;i=Next[i]){ int v=To[i]; if(!dfn[v]) { tarjan(v); low[u]=min(low[u],low[v]); } else if(instk[v])low[u]=min(low[u],dfn[v]);//無向圖與有向圖的區別 } if(dfn[u]==low[u]){ scc_cnt++; while(true){ int x=q[head--]; scc[x]=scc_cnt; V[scc_cnt]+=w[x]; instk[x]=0; if(x==u) break; } } }