#HDU 4612 Warm up (tarjan + 樹的直徑)

Warm up

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)
Total Submission(s): 10317    Accepted Submission(s): 2380


 

Problem Description

  N planets are connected by M bidirectional channels that allow instant transportation. It's always possible to travel between any two planets through these channels.
  If we can isolate some planets from others by breaking only one channel , the channel is called a bridge of the transportation system.
People don't like to be isolated. So they ask what's the minimal number of bridges they can have if they decide to build a new channel.
  Note that there could be more than one channel between two planets.

 

 

Input

  The input contains multiple cases.
  Each case starts with two positive integers N and M , indicating the number of planets and the number of channels.
  (2<=N<=200000, 1<=M<=1000000)
  Next M lines each contains two positive integers A and B, indicating a channel between planet A and B in the system. Planets are numbered by 1..N.
  A line with two integers '0' terminates the input.

 

 

Output

  For each case, output the minimal number of bridges after building a new channel in a line.

 

 

Sample Input


 

4 4 1 2 1 3 1 4 2 3 0 0

 

 

Sample Output


 

0

題目大意 : 有一個連通的無向圖, 現在要給這張圖添加一條邊, 讓你求添加一條邊以後,圖中橋的數量的最小值

思路 : 如果知道樹的直徑這個概念的話, 思路就不難想到, 要想使得橋的數量最小, 那麼一定讓圖的雙連通性最大, 也就是一條邊可以讓最多的點形成雙聯通,也就是樹的直徑了,所以先縮點,注意處理重邊,然後對這棵樹進行兩次dfs求出樹的直徑。

這些操作都很簡單,主要是題目對時間和內存要求比較高,平時這兩個地方不嚴謹的話很容易TLE或MLE

經過多次實驗,最穩妥的辦,法就是數組卡着內存開,點多用鏈式前向星, 縮完點後點少了用vector

Accepted code

#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<stack>
using namespace std;

#define sc scanf
#define ls rt << 1
#define rs ls | 1
#define Min(x, y) x = min(x, y)
#define Max(x, y) x = max(x, y)
#define ALL(x) (x).begin(),(x).end()
#define SZ(x) ((int)(x).size())
#define MEM(x, b) memset(x, b, sizeof(x))
#define lowbit(x) ((x) & -(x))
#define P2(x) ((x) * (x))

typedef long long ll;
const int MOD = 1e9 + 7;
const int MAXN = 1e6 + 100;
const int MAXM = 2e5 + 100;
const int INF = 0x3f3f3f3f;
inline ll fpow(ll a, ll b){ ll r = 1, t = a; while (b){ if (b & 1)r = (r*t) % MOD; b >>= 1; t = (t*t) % MOD; }return r; }

struct Edge
{
	int v, f, next;
}e[MAXN << 1];
vector <int> edge[MAXM];
int head[MAXM], n, m, cnt, tot, stot;
int dfn[MAXM], low[MAXM], suo[MAXM],  max_1, rt;
stack <int> st;
bool vis[MAXM];
void init() {
	MEM(head, -1); MEM(e, 0); MEM(vis, 0);
	MEM(dfn, 0); MEM(low, 0); MEM(suo, 0);
	cnt = tot = stot = 0;
}
void add(int from, int to) {
	e[cnt].v = to;
	e[cnt].next = head[from];
	head[from] = cnt++;
}
void tarjan(int x) {
	dfn[x] = low[x] = ++tot;
	st.push(x);
	for (int i = head[x]; i != -1; i = e[i].next) {
		int vi = e[i].v;
		if (e[i].f) continue;
		e[i].f = e[i ^ 1].f = 1;
		if (!dfn[vi]) {
			tarjan(vi);
			Min(low[x], low[vi]);
		}
		else Min(low[x], dfn[vi]);
	}
	if (dfn[x] == low[x]) {
		stot++; int k;
		do {
			k = st.top(); st.pop();
			suo[k] = stot;
		} while (k != x);
	}
}
void dfs(int x, int step) {
	vis[x] = true;
	if (step > max_1) max_1 = step, rt = x;
	for (int i = 0; i < SZ(edge[x]); i++) {
		int vi = edge[x][i];
		if (vis[vi]) continue;
		dfs(vi, step + 1);
	}
}

int main()
{
	while (~sc("%d %d", &n, &m) && n + m) {
		init();
		for (int i = 0; i < m; i++) {
			int ui, vi; sc("%d %d", &ui, &vi);
			add(ui, vi); add(vi, ui);
		}
		tarjan(1);
		for (int i = 1; i <= n; i++) {
			for (int j = head[i]; j != -1; j = e[j].next) {
				int ui = suo[i], vi = suo[e[j].v];
				if (ui != vi) edge[ui].push_back(vi);
			}
		}
		max_1 = 0; dfs(1, 0);
		MEM(vis, 0);
		max_1 = 0; dfs(rt, 0);
		printf("%d\n", stot - max_1 - 1);  // 樹的大小 - 直徑
		for (int i = 1; i <= stot; i++) edge[i].clear();
	}
	return 0;
}

 

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