Knights of the Round Table

prologue

相信很多人都感觉这个题不就是求一下这个二分图的最大独立集嘛,有什么难的,(劈里啪啦、库里跨啦、叮里哐啷)好,不对,好好好,题解!

analysis

这个题目实际上并不是一个完整的最大独立集问题,因为在这个题里面,是可以有相互仇恨的骑士的,只要不让他们二人坐成同桌就行。

那么我们就不如从正面来解决这个题。

首先,建立这个 憎恨 关系的 补图 从而得到一张 友善 关系图,这个时候肯定会形成环,我们进行下一步的思考。

之后,用 tarjan 将每个图所成一个点,之后对于每一个内部点数大于等于三的 V-DCC 进行判断内部是不是 奇环(题目中有描述,每次会议只能是奇数个人),如果这个环内部的数量不是奇数,那么这环内部的骑士就不能参与会议,属于要被除名的人。

对于判断每一个环是不是奇环,我们可以用 染色法,如果发生 冲突 则代表内部是合法的,如果成功染色,则是 非法 的。

同时还有一个重要结论虽然我不知道为什么重要,大佬说是就是点双连通图中若包含一个奇环,则所有点都在至少一个简单奇环上。

至于证明过程,大家可以前往巨佬的博客查看。

CODE TIME

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

const ll N = 1010;

ll n, m;

ll dfn[N], low[N], top, timestamp, ans, tmp[N];

ll stk[N], dcc_cnt, dcc_size[N], col[N], root, now;

bool g[N][N], val[N], in_dcc[N], flag;

vector<ll> dcc[N];

inline void dfs(ll u, ll c)
{
	if(flag) return ;
	col[u] = c;
	for(rl i=1; i <= n; ++ i) if(g[u][i])
	{
		if(tmp[i] != now) continue;
		if(col[i]) if(col[i] == c) { flag = 1; return ;}
		if(!col[i]) dfs(i, 3 - c);
	}
}

inline void tarjan(ll u)
{
	stk[ ++ top] = u;
	dfn[u] = low[u] = ++ timestamp;
	
	for(rl v=1; v <= n; ++ v)
	{
		if(!g[u][v]) continue;
		if(!dfn[v])
		{
			tarjan(v), low[u] = min(low[u], low[v]);
			if(low[v] >= dfn[u])
			{
				dcc_cnt ++ ;
				ll ele;
				do {
					ele = stk[top -- ];
					dcc[dcc_cnt].push_back(ele), dcc_size[dcc_cnt] ++ ;
				} while(ele != v);
				dcc[dcc_cnt].push_back(u), dcc_size[dcc_cnt] ++;
			}
		}
		else low[u] = min(low[u], dfn[v]);
	}
}

inline void clean()
{
	for(rl i=1; i <= dcc_cnt; ++ i) dcc[i].clear();
	top = timestamp = dcc_cnt = ans = 0;
	memset(dcc_size, 0, sizeof dcc_size), memset(dfn, 0, sizeof dfn), memset(tmp, 0, sizeof tmp);
	memset(g, 0, sizeof g), memset(col, 0, sizeof col), memset(val, 0, sizeof val);
}

int main()
{
	while(cin >> n >> m, n)
	{
		clean();
		for(rl i=1; i <= n; ++ i) g[i][i] = 1;
		for(rl i=1; i <= m; ++ i)
		{
			ll a, b;
			cin >> a >> b;
			g[a][b] = g[b][a] = true;
		}
		
		for(rl i=1; i <= n; ++ i)
			for(rl j=1; j <= n; ++ j)
				g[i][j] ^= 1;
				
		for(root = 1; root <= n; ++ root)
			if(!dfn[root])
				tarjan(root);
		
		for(rl i=1; i <= dcc_cnt; ++ i)
		{
			now = i, flag = 0;
			for(rl j : dcc[i]) tmp[j] = now, col[j] = 0;
			dfs(dcc[i][0], 1);
			if(flag)
				for(rl j : dcc[i])
					val[j] = true;
		}
		
		for(rl i=1; i <= n; ++ i) ans += val[i];
			
		cout << n - ans << endl;
	}
	return 0;
}
posted @ 2023-09-26 16:52  carp_oier  阅读(22)  评论(0)    收藏  举报