UVa 1364

题目链接:https://onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&category=0&problem=4110&mosmsg=Submission+received+with+ID+26571544

如果两个骑士不互相讨厌,即可以相邻,则参加会议的骑士在无向图中组成简单奇圈。简单圈上的所有结点必定属于同一个双连通分量,所以要先找出所有的双连通分量。而二分图是没有奇圈的,所以找出不是二分图的双连通分量,对双连通分量二分图染色判断即可。可以证明,存在奇圈的双连通分量中的所有节点都在奇圈上。给这些双连通分量中的点打上标记统计答案即可。

时间复杂度 (O(n))

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxn = 1010; 
const int maxm = 1000010;

int n, m;
int g[maxn][maxn];

int h[maxn], cnt = 0;
struct E{
	int from, to, next;
}e[maxm << 1];
void add(int u, int v){
	e[++cnt].to = v;
	e[cnt].from = u;
	e[cnt].next = h[u];
	h[u] = cnt;
}

stack<E> s;
vector<int> bcc[maxn];

int st[maxn], iscut[maxn], bccno[maxn], low[maxn], dfn = 0, bcc_cnt = 0;

int dfs(int u, int par){
	int lowu = st[u] = ++dfn;
	int child = 0;
	for(int i = h[u] ; i != -1 ; i = e[i].next){
		int v = e[i].to;
		E e = (E){u, v, -1};
		if(!st[v]){
			s.push(e);
			++child;
			int lowv = dfs(v, u); 
			lowu = min(lowu, lowv);
			if(lowv >= st[u]){
				iscut[u] = 1;
				bcc_cnt++; 
				bcc[bcc_cnt].clear();
				for(;;){
					E x = s.top(); s.pop();
					if(bccno[x.from] != bcc_cnt){ bcc[bcc_cnt].push_back(x.from); bccno[x.from] = bcc_cnt; }
					if(bccno[x.to] != bcc_cnt){ bcc[bcc_cnt].push_back(x.to); bccno[x.to] = bcc_cnt; }
					if(x.from == u && x.to == v) break;
				}
			}
		} else if(st[v] < st[u] && v != par){ // 反向边更新 
			s.push(e);
			lowu = min(lowu, st[v]);
		}
	}
	if(par == 0 && child == 1) iscut[u] = 0;
	low[u] = lowu;
	return low[u];
}

void tarjan(){
	memset(st, 0, sizeof(st));
	memset(iscut, 0, sizeof(iscut));
	memset(bccno, 0, sizeof(bccno));
	dfn = bcc_cnt = 0;
	 
	for(int i = 1 ; i <= n ; ++i){
		if(!st[i]) dfs(i, 0);
	}
}

int odd[maxn], color[maxn];

bool bipartite(int u, int b){
	for(int i = h[u] ; i != -1 ; i = e[i].next){
		int v = e[i].to;
		if(bccno[v] != b) continue;
		if(color[v] == color[u]) return false;
		if(!color[v]){
			color[v] = 3 - color[u];
			if(!bipartite(v, b)) return false;		
		}
	}
	return true;
} 

ll read(){ ll s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); } return s * f; }

int main(){
	while(scanf("%d%d", &n, &m) == 2 && n){
		memset(h, -1, sizeof(h)); cnt = 0; dfn = 0;
		memset(g, 0, sizeof(g));
		
		int u, v;
		for(int i = 1 ; i <= m ; ++i){
			scanf("%d%d", &u, &v);
			g[u][v] = g[v][u] = 1;
		}
		
		for(int i = 1 ; i <= n ; ++i){
			for(int j = i + 1 ; j <= n ; ++j){
				if(!g[i][j]) {
					add(i, j); add(j, i);
				}
			}
		}
		
		tarjan();
		
		memset(odd, 0, sizeof(odd));
		for(int i = 1 ; i <= bcc_cnt ; ++i){
			memset(color, 0, sizeof(color));
			for(int j = 0 ; j < bcc[i].size() ; ++j) bccno[bcc[i][j]] = i;
			int u = bcc[i][0];
			color[u] = 1;
			
			if(!bipartite(u, i)){
				for(int j = 0 ; j < bcc[i].size() ; ++j) odd[bcc[i][j]] = 1;
			}
		}
		
		int ans = n; 
		for(int i = 1 ; i <= n ; ++i) if(odd[i]) --ans;
		printf("%d
", ans); 
	}
	return 0;
}
原文地址:https://www.cnblogs.com/tuchen/p/15013328.html