AcWing 365. 圓桌騎士

題目鏈接:傳送門

有仇恨的騎士不能相鄰,那就在沒有仇恨的騎士之間連邊,意義就是他們可以相鄰
要求騎士的座位形成一個環,那麼入度爲0或者爲1的騎士是無法被加進來的
而且要求環是有奇數個點,這就用到判斷奇環的方法,其實就是判斷這個圖是不是二分圖,交叉染色判斷即可
找到每個符合條件的環之後將環內的騎士標號,最後答案減去這些騎士就是要被踢出去的
這裏的環要用判斷割點的方法而不能縮點,因爲我們只需要找到一個個的連通分量,從小的環開始判斷才能獲得更多的環使答案更優

#include <bits/stdc++.h>
#define A 1010
#define B 2000010

using namespace std;
typedef long long ll;
struct node {int next, to;}e[B];
int head[A], num;
void add(int fr, int to) {e[++num].next = head[fr]; e[num].to = to; head[fr] = num;}
int n, m, a, b; bool hate[A][A], exi[A], bl[A];
int dfn[A], cnt, low[A], col[A], sta[A], top;
vector<int> v;
bool check(int s) {
	queue<int> q; q.push(s); col[s] = 1;
	while (!q.empty()) {
		int fr = q.front(); q.pop(); int color = (col[fr] == 1 ? 2 : 1);
		for (int i = head[fr]; i; i = e[i].next) {
			int ca = e[i].to;
			if (!exi[ca]) continue;
			if (!col[ca]) col[ca] = color, q.push(ca);
			else if (col[ca] != color) return true;
		}
	}
	return false;
}
void tarjan(int fr) {
	dfn[fr] = low[fr] = ++cnt; sta[++top] = fr;
	for (int i = head[fr]; i; i = e[i].next) {
		int ca = e[i].to;
		if (!dfn[ca]) {
			tarjan(ca); low[fr] = min(low[fr], low[ca]);
			if (dfn[fr] <= low[ca]) {
				v.clear(); int p;
				do {
					p = sta[top--];
					v.push_back(p);
				} while (p != ca);
				v.push_back(fr);
				memset(col, 0, sizeof col); memset(exi, 0, sizeof exi);
				for (auto j : v) exi[j] = 1;
				if (check(v[0])) for (auto j : v) bl[j] = 1;
			}
		}
		else low[fr] = min(low[fr], dfn[ca]);
	}
}

int main(int argc, char const *argv[]) {
	while (scanf("%d%d", &n, &m) and n and m) {
		memset(head, 0, sizeof head); num = 0; cnt = 0; memset(bl, 0, sizeof bl);
		memset(dfn, 0, sizeof dfn); memset(low, 0, sizeof low); top = 0;
		memset(sta, 0, sizeof sta); memset(hate, 0, sizeof hate);
		for (int i = 1; i <= m; i++) scanf("%d%d", &a, &b), hate[a][b] = hate[b][a] = 1;
		for (int i = 1; i <= n; i++)
			for (int j = i + 1; j <= n; j++)
				if (!hate[i][j]) add(i, j), add(j, i);
		for (int i = 1; i <= n; i++) if (!dfn[i]) tarjan(i);
		int ans = n;
		for (int i = 1; i <= n; i++) if (bl[i]) ans--;
		printf("%d\n", ans);
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章