Knights of the Round Table

转化模型为在求一个无向图中不属于任何简单奇圈的点的个数,我们可以求出所有属于简单奇圈的点剩下的点就是答案,首先求在一个简单圈中的点,显然是求点双连通分量(俩个点的点双连通分量不是简单圈,但在后面判断二分图时会把这种情况排除掉),二分图与不存在奇圈的图是等价定义,所以只要在求出点双连通分量后判断每个连通分量是否是二分图(因为如果子原图是二分图,那么其子图必定也是二分图,所以只要判断连通分量是不是二分图就可以了).


#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <queue>
#include <algorithm>
#include <vector>
#include <cstring>
#include <stack>
#include <cctype>
#include <utility>   
#include <map>
#include <string>  
#include <climits> 
#include <set>
#include <string>    
#include <sstream>
#include <utility>   
#include <ctime>

using std::priority_queue;
using std::vector;
using std::swap;
using std::stack;
using std::sort;
using std::max;
using std::min;
using std::pair;
using std::map;
using std::string;
using std::cin;
using std::cout;
using std::set;
using std::queue;
using std::string;
using std::istringstream;
using std::make_pair;
using std::greater;
using std::endl;

const int MAXN(1010);
const int MAXE(2000010);

struct EDGE
{
	int u, v;
	int next;
};

int first[MAXN], rear;
EDGE edge[MAXE];

void init()
{
	memset(first, -1, sizeof(first));
	rear = 0;
}

void insert(int tu, int tv)
{
	edge[rear].u = tu;
	edge[rear].v = tv;
	edge[rear].next = first[tu];
	first[tu] = rear++;
}

int pre[MAXN], low[MAXN], bccno[MAXN];
bool is_cut[MAXN];
stack<int> st;
vector<int> bcc[MAXN];
int dfs_clock, bcc_cnt;

//接着在不经过桥的情况下dfs求出所有双强连通分量即可
//在求解点和边的连通分量时,连接到自己的边都没有意义

int dfs(int cur, int fa)
{
	pre[cur] = low[cur] = ++dfs_clock;
	int child(0);
	for(int i = first[cur]; i != -1; i = edge[i].next)
	{
		int tv = edge[i].v;
		if(!pre[tv])
		{
			++child;
			st.push(i);
			int lowv = dfs(tv, cur);
			low[cur] = min(low[cur], lowv);
			if(lowv >= pre[cur])
			{
				is_cut[cur] = true;
				++bcc_cnt;
				bcc[bcc_cnt].clear();
				int temp;
				while(true)
				{
					temp = st.top();
					st.pop();
					if(bccno[edge[temp].u] != bcc_cnt)
					{
						bccno[edge[temp].u] = bcc_cnt;
						bcc[bcc_cnt].push_back(edge[temp].u);
					}
					if(bccno[edge[temp].v] != bcc_cnt)
					{
						bccno[edge[temp].v] = bcc_cnt;
						bcc[bcc_cnt].push_back(edge[temp].v);
					}
					if(temp == i)
						break;
				}
			}
		}
		else
			if(pre[tv] < pre[cur] && tv != fa)
			{
				st.push(i);
				low[cur] = min(low[cur], pre[edge[i].v]);
			}
	}
	if(fa == -1 && child > 1)
		is_cut[cur] = true;
	return low[cur];
}

void find_bcc(int n)
{
	dfs_clock = bcc_cnt = 0;
	memset(pre, 0, sizeof(pre));
	memset(low, 0, sizeof(low));
	memset(bccno, 0, sizeof(bccno));
	memset(is_cut, 0, sizeof(is_cut));
	for(int i = 1; i <= n; ++i)
		if(!pre[i])
			dfs(i, -1);
}

int color[MAXN];

bool isbipartite(int cur, int no)
{
	for(int i = first[cur]; i != -1; i = edge[i].next)
	{
		int tv = edge[i].v;
		if(bccno[tv] == no)
		{
			if(!color[tv])
			{
				color[tv] = 3-color[cur];
				if(!isbipartite(tv, no))
					return false;
			}
			else
				if(color[tv] == color[cur])
					return false;
		}
	}
	return true;
}

bool odd[MAXN];
bool hate[MAXN][MAXN];

int main()
{
	int n, m;
	while(scanf("%d%d", &n, &m), n+m)
	{
		init();
		memset(hate, 0, sizeof(hate));
		int tu, tv;
		for(int i = 0; i < m; ++i)
		{
			scanf("%d%d", &tu, &tv);
			hate[tu][tv] = true;
			hate[tv][tu] = true;
		}
		for(int i = 1; i <= n; ++i)
			for(int j = i+1; j <= n; ++j)
				if(!hate[i][j])
				{
					insert(i, j);
					insert(j, i);
				}
		find_bcc(n);
		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 cur = bcc[i][0];
			color[cur] = 1;
			if(!isbipartite(cur, i))
				for(int j = 0; j < bcc[i].size(); ++j)
					odd[bcc[i][j]] = true;
		}
		int ans = 0;
		for(int i = 1; i <= n; ++i)
			if(!odd[i])
				++ans;
		printf("%d\n", ans);
	}
	return 0;
}


你可能感兴趣的:(Knights of the Round Table)