牛客小白月賽12(i)華華和月月逛公園

題目: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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章