題目:https://ac.nowcoder.com/acm/contest/392/I
首先先了解一下什麼是割邊割點!!!
割邊:在無向圖中,如果刪除圖中的一條邊,圖的連通分量增加,那就稱該邊爲割邊。(割邊可以有多個)
割點:同理,在無向圖中如果刪除圖中的一個頂點及頂點的鄰邊,圖的連通分量增加,則稱該點爲割點。(割點也可以有多個)
方法:tarjin算法找割邊的數量ans(割邊是一定要走的邊),所以不一定要走的邊的數量爲m-ans。
這裏,解釋一下爲什麼要找割邊,(畫個圖會很清楚的看出來)就拿題目的樣例(如下)來說,{1,2,3,4,5}構成了個連通分量,如果我刪除1to2或者2to3這個邊,那麼連通分量會變成{1},{2,3,4,5}或者{1,2},{3,4,5},與此同時,會導致所有的景點無法完全經過,因爲割邊是連接兩端連通分量的唯一邊!!!
5 5
1 2
2 3
3 4
4 5
3 5
#include<iostream>
#include<list>
using namespace std;
const int maxn=100005;
int low[maxn],dfn[maxn],ans,p; //dfn數組記錄第一次經過這個頂點(下標)的時間戳,low記錄的是可以經過這個頂點的最小時間戳(會在遞歸後進行更新得到最小的時間戳),ans記錄割邊的數量,p爲當前時間戳
list<int> g[maxn];
list<int> sta; //沒啥用。
void dfs(int u,int fa) //此處的dfs即爲tarjin算法的遍歷方法
{
low[u]=dfn[u]=++p; //初始化兩個時間戳數組
// cout<<u<<endl;
for(list<int >::iterator i=g[u].begin();i!=g[u].end();i++)
{
int v=*i;
if(v==fa) continue;
if(!low[v])
{
dfs(v,u);
low[u]=min(low[v],low[u]); //遞歸後更新當前點的最小時間戳,將dfs盡頭的頂點的low傳遞下來,表示當前頂點屬於某個連通分量
if(low[v]>dfn[u]) ans++; //記錄割邊的數量,如果' > '改成' >= '則ans是割點數量+1
}
else if(dfn[v]) low[u]=min(low[u],low[v]); //遍歷到頂點v,如果v已經遍歷過的,則取v的low時間戳給u
}
// cout<<endl;
}
int main()
{
int n,m;
cin>>n>>m;
for(int i=0;i<m;i++)
{
int u,v;
cin>>u>>v;
g[u].push_back(v);
g[v].push_back(u);
}
dfs(1,0);
// for(int i=1;i<=n;i++) cout<<low[i]<<' '<<dfn[i]<<endl;
cout<<m-ans<<endl;
return 0;
}