> 文档中心 > Knights of the Round Table

Knights of the Round Table


Description

POJ2942

Being a knight is a very attractive career: searching for the Holy
Grail, saving damsels in distress, and drinking with the other knights
are fun things to do. Therefore, it is not very surprising that in
recent years the kingdom of King Arthur has experienced an
unprecedented increase in the number of knights. There are so many
knights now, that it is very rare that every Knight of the Round Table
can come at the same time to Camelot and sit around the round table;
usually only a small group of the knights isthere, while the rest are
busy doing heroic deeds around the country.

Knights can easily get over-excited during discussions-especially
after a couple of drinks. After some unfortunate accidents, King
Arthur asked the famous wizard Merlin to make sure that in the future
no fights break out between the knights. After studying the problem
carefully, Merlin realized that the fights can only be prevented if
the knights are seated according to the following two rules:

The knights should be seated such that two knights who hate each other
should not be neighbors at the table. (Merlin has a list that says who
hates whom.) The knights are sitting around a roundtable, thus every
knight has exactly two neighbors.

An odd number of knights should sit around the table. This ensures
that if the knights cannot agree on something, then they can settle
the issue by voting. (If the number of knights is even, then itcan
happen that yes" andno" have the same number of votes, and the
argument goes on.)

Merlin will let the knights sit down only if these two rules are
satisfied, otherwise he cancels the meeting. (If only one knight shows
up, then the meeting is canceled as well, as one person cannot sit
around a table.) Merlin realized that this means that there can be
knights who cannot be part of any seating arrangements that respect
these rules, and these knights will never be able to sit at the Round
Table (one such case is if a knight hates every other knight, but
there are many other possible reasons). If a knight cannot sit at the
Round Table, then he cannot be a member of the Knights of the Round
Table and must be expelled from the order. These knights have to be
transferred to a less-prestigious order, such as the Knights of the
Square Table, the Knights of the Octagonal Table, or the Knights of
the Banana-Shaped Table. To help Merlin, you have to write a program
that will determine the number of knights that must be expelled.

翻译:

做一个骑士是一个非常有吸引力的职业:寻找圣杯,拯救处于困境中的少女,和其他骑士一起喝酒都是很有趣的事情。因此,近年来亚瑟王国骑士人数空前增加,这并不奇怪。现在骑士太多了,圆桌会议上的每一位骑士都能同时来到卡米洛特,围坐在圆桌旁,通常只有一小部分骑士在这里,其余的骑士则忙着在全国各地做英雄事迹。

骑士们在讨论时很容易过度兴奋,尤其是在喝了几杯酒之后。在发生了一些不幸的意外之后,亚瑟王要求著名的巫师梅林确保骑士们今后不再发生争斗。在仔细研究了这个问题后,梅林意识到,只有骑士们按照以下两个规则就座,才能避免打斗:

骑士们的座位应该是这样的:两个互相憎恨的骑士不应该成为餐桌上的邻居。(梅林有一张名单,上面写着谁恨谁。)骑士们围坐在圆桌旁,因此每个骑士都有两个邻居。

围坐在桌子旁边应该是奇数个骑士。这就保证了如果骑士们不能就某件事达成一致,那么他们可以通过投票来解决问题。(如果骑士的数目是偶数,那么“是”和“否”的票数可能相同,争论继续下去。)

梅林只有在满足这两条规则的情况下才会让骑士们坐下,否则他取消会议。(如果只有一个骑士出现,那么会议也会取消,因为一个人不能围坐在桌子旁边。)梅林意识到这意味着有骑士不能参加任何尊重这些规则的座位安排,这些骑士永远也不能坐在圆桌上(一个这样的例子是如果一个骑士憎恨其他所有的骑士,但是还有很多其他可能的原因)。如果一个骑士不能坐在圆桌会议上,那么他就不能成为圆桌骑士团的成员,必须被驱逐出该骑士团。这些骑士必须转移到声望较低的骑士团,比如方桌骑士团、八角桌骑士团或香蕉形桌骑士团。为了帮助梅林,你必须编写一个程序来确定必须驱逐的骑士人数。

Input

输入包含多组测试数据。每组测试数据都以一行包含两个整数n,m
1≤n≤1000和1≤m≤1000000开始。数字n是骑士的数目。接下来的m行描述了哪个骑士讨厌哪个骑士。这些m行中的每一行都包含两个整数k1和k2,这意味着骑士编号k1和骑士编号k2彼此憎恨(数字k1和k2介于1和n之间)。

最后一行为 0 0

Output

对于每组测试数据,你必须在一行单独输出一个整数:必须驱逐的骑士数量。

Sample Input5 51 41 52 53 44 50 0Sample Output2

CODE

#include#include#include#include#includeusing namespace std;const int N = 1010, M = 2000010;int head[N], ver[M], Next[M];int dfn[N], low[N], stack[N];int c[N], v[N], able[N];int n, m, tot, num, top, cnt, now;bool hate[N][N], flag;vector<int> dcc[N];void add(int x, int y) {ver[++tot] = y, Next[tot] = head[x], head[x] = tot;}void tarjan(int x, int root) {dfn[x] = low[x] = ++num;stack[++top] = x;if (x == root && head[x] == 0) { // 孤立点dcc[++cnt].push_back(x);return;}for (int i = head[x]; i; i = Next[i]) {int y = ver[i];if (!dfn[y]) {tarjan(y, root);low[x] = min(low[x], low[y]);if (low[y] >= dfn[x]) {cnt++;int z;do {z = stack[top--];dcc[cnt].push_back(z);} while (z != y);dcc[cnt].push_back(x);}}else low[x] = min(low[x], dfn[y]);}}void dfs(int x, int color) {c[x] = color;for (int i = head[x]; i; i = Next[i]) {int y = ver[i];if (v[y] != now) continue;if (c[y] && c[y] == color) {flag = 1;return;}if (!c[y]) dfs(y, 3 - color);}}int main() {while (cin >> n >> m && n) {// 清零memset(head, 0, sizeof(head));memset(dfn, 0, sizeof(dfn));memset(able, 0, sizeof(able));memset(v, 0, sizeof(v));for (int i = 1; i <= n; i++) dcc[i].clear();tot = 1; num = top = cnt = 0;for (int i = 1; i <= n; i++)for (int j = 1; j <= n; j++) hate[i][j] = 0;for (int i = 1; i <= m; i++) {int x, y;scanf("%d%d", &x, &y);if (x == y) continue;hate[x][y] = hate[y][x] = 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, i);// 判断每个点双是否包含奇环for (int i = 1; i <= cnt; i++) {now = i;for (int j = 0; j < dcc[i].size(); j++)v[dcc[i][j]] = now, c[dcc[i][j]] = 0;flag = false;dfs(dcc[i][0], 1);if (flag)for (int j = 0; j < dcc[i].size(); j++)able[dcc[i][j]] = 1;}int ans = 0;for (int i = 1; i <= n; i++)if (!able[i]) ans++;cout << ans << endl;}}

希望可以帮助到大家!

明天再见,拜拜!

安全期查询