1. 程式人生 > >TopCoder SRM 682 Div1 Problem 450 SuccessfulMerger (環套樹 + 分類討論)

TopCoder SRM 682 Div1 Problem 450 SuccessfulMerger (環套樹 + 分類討論)

特殊 com 新的 比較 -- ace info cpp ear

題意 給定一個$n$個點$n$條邊的無向圖,現在要把這個圖進行若幹次操作,並選擇一個點作為首都。

   要求除首都外的任意兩個點$u$, $v$,從$u$走到$v$必須經過這個首都。

操作為合並兩個相鄰的點為一個點,即把這兩個點從原圖中刪除,連接這兩個點的邊接到新的點上去。

考慮最後這個圖的形態其實是一個菊花圖,那麽可以考慮到最後剩下的這些點其實只有選出的首都和

原圖中度數為$1$的點。

但是有這麽一種比較特殊的情況。

技術分享圖片

這個圖也是符合題意的。

原來的圖其實是一個環套樹(環的大小可能為$2$)

如果這個環上存在一個度數為$2$的點(即除了和環上的點相連之外其他沒有點和他相連)

那麽這個點也可以被留下,但是所有這樣的點中最多只能留下一個。

於是答案就很顯然了。

#include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b)	for (int i(a); i <= (b); ++i)
#define dec(i, a, b)	for (int i(a); i >= (b); --i)
#define MP		make_pair

typedef long long LL;
typedef pair <int, int> PII;

const int N = 105;

int vis[N], father[N], isroot[N], a[N];
int cnt;
int flag;
int n, now, ans;
int xx, yy;
map <PII, int> mp;
vector <int> v[N];

int get_circle(int x){
	vis[x] = 1;
	for (auto u : v[x]){
		if (u == father[x]) continue;
		father[u] = x;
		if (vis[u]){
			cnt = 0;
			int w = x;
			while (w ^ u){
				a[++cnt] = w;
				isroot[w] = cnt;
				w = father[w];
			}

			a[++cnt] = u;
			isroot[u] = cnt;
			return 1;
		}

		if (get_circle(u)) return 1;
	}
	
	return 0;
}

void dfs(int x){
	vis[x] = 1;
	for (auto u : v[x]){
		if (vis[u] || isroot[u]) continue;
		dfs(u);
	}
}

class SuccessfulMerger{
	public:
		int minimumMergers(vector<int> road){
			memset(a, 0, sizeof a);
			memset(isroot, 0, sizeof isroot);
			memset(father, 0, sizeof father);
			memset(vis, 0, sizeof vis);
			cnt = 0;
			n = 0;
			flag = 0;
			mp.clear();
			rep(i, 0, 100) v[i].clear();
			for (auto u : road){
				++n;
				++u;
				int x = n, y = u;
				if (x > y) swap(x, y);
				if (mp.count(MP(x, y))){
					flag = 1;
					xx = x, yy = y;
					continue;
				}

				mp[MP(x, y)] = 1;
				v[x].push_back(y);
				v[y].push_back(x);
			}


			if (flag){
				cnt = 2;
				a[1] = xx;
				a[2] = yy;
			}

			else get_circle(1);

			if (flag){
				v[xx].push_back(yy);
				v[yy].push_back(xx);
			}

			ans = n - 1;
			rep(i, 1, n) if ((int)v[i].size() == 1) --ans;

			rep(i, 1, cnt){
				int ccc = 0;
				for (auto u : v[a[i]]){
					int fg = 0;
					rep(j, 1, cnt) if (u == a[j]) fg = 1;
					if (fg == 0) ccc = 1;
				}

				if (ccc == 0){ --ans; break; }
			}

			return ans;
		}
};

  

TopCoder SRM 682 Div1 Problem 450 SuccessfulMerger (環套樹 + 分類討論)