[UVA1364] [POJ2942] Knights of the Round Table

7 篇文章 0 订阅
3 篇文章 0 订阅
POJ传送门
Luogu传送门
UVA传送门

题意翻译

亚瑟王要在圆桌上召开骑士会议,为了不引发骑士之间的冲突,并且能够让会议的议题有令人满意的结果,每次开会前都必须对出席会议的骑士有如下要求:

1、 相互憎恨的两个骑士不能坐在直接相邻的2个位置;

2、 出席会议的骑士数必须是奇数,这是为了让投票表决议题时都能有结果。

如果出现有某些骑士无法出席所有会议(例如这个骑士憎恨所有的其他骑士),则亚瑟王为了世界和平会强制把他剔除出骑士团。

​ 现在给定准备去开会的骑士数 n n n,再给出 m m m对憎恨对(表示某 2 2 2个骑士之间使互相憎恨的),问亚瑟王至少要剔除多少个骑士才能顺利召开会议?

注意:

1.所给出的憎恨关系一定是双向的,不存在单向憎恨关系。

2.由于是圆桌会议,则每个出席的骑士身边必定刚好有 2 2 2个骑士。即每个骑士的座位两边都必定各有一个骑士。

3.一个骑士无法开会,就是说至少有 3 3 3个骑士才可能开会。

输入输出格式

输入格式

题目包含多组数据。

每一组数据的第一行为两个整数 n , m n,m n,m。 如果 n = m = 0 n=m=0 n=m=0则代表输入结束, 你不必处理这组数据。

以下 m m m行, 每行两个正整数, 表示一组憎恨关系。

输出格式

对于每组数据, 输出一行一个正整数, 表示最少需要剔除掉的骑士个数。

输入输出样例

输入样例
5 5
1 4
1 5
2 5
3 4
4 5
0 0
输出样例
2

解题分析

来补点双的锅了QAQ

首先, 我们把这个图转成其补图, 那么问题就变成了有多少个点不在任何一个奇环中。

注意到任何一个点双中, 如果有一个奇环, 那么所有点都可以至少在一个奇环中(因为奇环会被拆成两部分, 一截长度为偶数, 一截为奇数, 而点双中无割点, 我们可以选一条凑出一个奇环)。

所以我们直接缩点双, 然后大力染色判奇环即可。

代码如下:

#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <algorithm>
#include <cstring>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define MX 1050
template <class T>
IN void in(T &x)
{
	x = 0; R char c = gc;
	for (; !isdigit(c); c = gc);
	for (;  isdigit(c); c = gc)
	x = (x << 1) + (x << 3) + c - 48;
}
template <class T> IN T min(T a, T b) {return a < b ? a : b;}
template <class T> IN T max(T a, T b) {return a > b ? a : b;}


int n, m, cnt, arr, top, tot;
struct Edge {int to, nex;} edge[MX * MX * 2];
int head[MX], col[MX], low[MX], dfn[MX], buc[MX], sta[MX];
bool mp[MX][MX], ok[MX], init[MX];
IN void add(R int from, R int to)
{edge[++cnt] = (Edge){to, head[from]}, head[from] = cnt;}

bool dye(R int now, R int fa, R int cl)
{
	col[now] = cl;
	for (R int i = head[now]; i; i = edge[i].nex)
	{
		if (!init[edge[i].to]) continue;
		if (~col[edge[i].to])
		{
			if (col[edge[i].to] == col[now]) return false;
			else continue;
		}
		else if (!dye(edge[i].to, now, cl ^ 1)) return false;
	}
	return true;
}
void DFS(R int now, R int fa)
{
	dfn[now] = low[now] = ++arr;
	sta[++top] = now;
	for (R int i = head[now]; i; i = edge[i].nex)
	{
		if (edge[i].to == fa) continue;
		if (!dfn[edge[i].to])
		{
			DFS(edge[i].to, now);
			low[now] = min(low[now], low[edge[i].to]);
			if (low[edge[i].to] >= dfn[now])
			{
				tot = 0;
				do {buc[++tot] = sta[top--];}
				W (buc[tot] ^ edge[i].to);
				if (tot == 1) continue;
				buc[++tot] = now;
				for (R int j = 1; j <= tot; ++j) init[buc[j]] = true, col[buc[j]] = -1;
				if (!dye(now, 0, 0))
				for (R int j = 1; j <= tot; ++j) ok[buc[j]] = true;
				for (R int j = 1; j <= tot; ++j) init[buc[j]] = false;
			}
		}
		else low[now] = min(low[now], dfn[edge[i].to]);
	}
}
int main(void)
{
	int foo, bar, ans;
	W (233)
	{
		std::memset(head, arr = cnt = 0, sizeof(head));
		std::memset(mp, false, sizeof(mp));
		std::memset(ok, false, sizeof(ok));
		std::memset(dfn, ans = 0, sizeof(dfn));
		in(n), in(m);
		if (n == 0 && m == 0) break;
		for (R int i = 1; i <= m; ++i)
		{
			in(foo), in(bar);
			mp[foo][bar] = true;
			mp[bar][foo] = true;
		}
		for (R int i = 1; i < n; ++i)
		for (R int j = i + 1; j <= n; ++j)
		if (!mp[i][j]) add(i, j), add(j, i);
		for (R int i = 1; i <= n; ++i) if (!dfn[i]) DFS(i, 0);
		for (R int i = 1; i <= n; ++i) if (ok[i]) ++ans;
		printf("%d\n", n - ans);
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值