HDU4587(TWO NODES)

題目傳送門
在這裏插入圖片描述

思路

題目很簡單,就是任意刪除兩個點,然後刪除兩個點之後的連通分量最多的數目是多少。拿到題大概率的感覺是這出題人xxx了吧,給這麼長時間,不嘗試一發最最最暴力的方法都對不起12000ms的時長。然後就去雙重循環枚舉刪除的點,跑裸的搜索,跑幾次搜索就有幾個連通分量然後一交TLE。12000ms好像對5000個點還是不夠啊。

正確的姿勢:枚舉刪除一個點a,在刪除a點的情況下做tarjan算法求割點,然後在枚舉每個點作爲刪除的第二個點b(b != a),找最大的連通分量數目就是答案。

  1. 對於樹根節點的連通分量是孩子數目減1,因爲跑一次Tarjan就是一個連通分量,如果你刪掉這個Tarjan生成樹的根節點實際上連通分量不增加。相當於一條手鍊從頭部拿掉一個珠子變成了一條手鍊 + 一顆珠子(刪除的割點)。
  2. 對於非樹根節點刪掉割點會增加一個連通分量。相當於一條手鍊從中間挖掉一個珠子就變成了兩條鏈 + 1個珠子(刪除的割點)。
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <algorithm>				
#include <cmath>
#include <iostream>
using namespace std;		
#pragma warning(disable:4996)
const int maxn = 5005;
struct edge{
	int to;
	int next;
}e[maxn<<1];
int head[maxn];
int s[maxn];
int dfn[maxn];
int low[maxn];
int tot,cnt;
int vis,root;
inline void clear_set()
{
	cnt = 0;
	memset(dfn,0,sizeof(dfn));
	memset(low,0,sizeof(low));
	memset(s,0,sizeof(s));
}
inline void addedge(int x,int y)
{
	e[tot].to = y;
	e[tot].next = head[x];
	head[x] = tot++;
}
inline void tarjan(int x,int fx)
{
	dfn[x] = low[x] = ++cnt;
	int son = 0;
	for(int i = head[x];~i;i = e[i].next){
		int y = e[i].to;
		if(y == vis || y == fx)	continue;			//不能走刪除的一號點,不能往回走到父節點
		if(!dfn[y]){
			son++;							
			tarjan(y,x);
			low[x] = min(low[x],low[y]);
			if(x != root && low[y] >= dfn[x]){
				s[x]++;					//該割點下的連通分量數目
			}
		}
		else if(dfn[y] < dfn[x]){
			low[x] = min(low[x],dfn[y]);
		}
	}
	if(x == root){				//樹根的連通分量是孩子數目-1	
		s[x] = son - 1;
	}
}
int main()
{
	int n,m;
	while(~scanf("%d%d",&n,&m)){
		tot = 0;
		memset(head,-1,sizeof(head));
		for(int i = 0;i < m;i++){
			int x,y;
			scanf("%d%d",&x,&y);
			addedge(x,y);	addedge(y,x);
		}
		int sum = 0;
		for(int j = 0;j < n;j++){			//枚舉刪除的一號點
			clear_set();
			int res = 0;
			vis = j;						//標記刪除的一號點
			for(int i = 0;i < n;i++){		//對當前刪除一號點的情況下做tarjan求割點
				if(i != j && !dfn[i]){		//不能對同一個點刪除兩次
					root = i;
					res++;					//幾次tarjan就有幾個連通分量
					tarjan(i,-1);
				}
			}
			int ans = 0;
			for(int i = 0;i < n;i++){		//枚舉刪除的二號點
				if(i != j){					//求出該割點下的連通分量數目
					sum = max(sum,res+s[i]);
				}
			}
		}
		printf("%d\n",sum);
	}
	return 0;
}

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

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