POJ2117(Electricity)

題目傳送門

在這裏插入圖片描述

題意

題目說了一堆廢話,簡單直白一點就是求割點,刪除哪個點之後連通分量最多(被刪除的哪個點不算),最開始給的圖可能就是一個不聯通的圖,最多有1萬個點,邊數不知道多少。

思路

  1. 由於圖可能不連通所以放在循環裏,對每個沒有時間序的點跑tarjan求割點,每跑一次tarjan就有一個聯通分量。
  2. 枚舉每一個點,計算刪除該點下的連通分量數目找到最大。
  3. 計算聯通分量直接在tarjan模板上做修改,但是要注意根節點和非根節點的連通塊數區別:根節點的連通塊是孩子數目 - 1,非根節點直接統計就可以。
  4. 由於邊不知道是多少,防止鏈式前向星邊數過大采用vector模擬鄰接表存圖,反正重邊無影響對割點不影響。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <algorithm>
#pragma warning(disable:4996)
using namespace std;
const int maxn = 10005;
vector<int>e[maxn];
int dfn[maxn];
int low[maxn];
int s[maxn];
int root,cnt;
inline void clear_set()
{
	for(int i = 0;i < maxn;i++){
		e[i].clear();
	}
	cnt = 0;
	memset(dfn,0,sizeof(dfn));
	memset(low,0,sizeof(low));
	memset(s,0,sizeof(s));
}
inline void tarjan(int x,int fx)
{
	dfn[x] = low[x] = ++cnt;
	int son = 0;
	for(int i = 0;i < e[x].size();i++){
		int y = e[x][i];
		if(!dfn[y]){
			son++;
			tarjan(y,x);
			low[x] = min(low[x],low[y]);
			if(low[y] >= dfn[x] && x != root){
				s[x]++;
			}
		}
		else if(y != fx && dfn[y] < dfn[x]){
			low[x] = min(low[x],dfn[y]);
		}
	}
	if(x == root){
		s[x] = son - 1;
	}
}
int main()
{
	int n,m;
	while(~scanf("%d%d",&n,&m)){
		if(n == 0 && m == 0)	break;
		clear_set();
		for(int i = 0;i < m;i++){
			int x,y;
			scanf("%d%d",&x,&y);
			e[x].push_back(y);
			e[y].push_back(x);
		}
		int sum = 0;
		for(int i = 0;i < n;i++){
			if(!dfn[i]){
				root = i;
				sum++;				//連通分量數目
				tarjan(i,-1);
			}	
		}
		int ans = 0;
		for(int i = 0;i < n;i++){
			ans = max(ans,sum+s[i]);
		}
		printf("%d\n",ans);
	}
	return 0;
}

願你走出半生,歸來仍是少年~

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