poj 2942--Knights of the Round Table (点的双连通分量)

做这题简直是一种折磨。。。

有n个骑士,骑士之间相互憎恨。给出骑士的相互憎恨的关系。 骑士要去开会,围成一圈坐,相互憎恨的骑士不能相邻。开会骑士的个数不能小于三个人。求有多少个骑士不能开会。

注意:会议可以开无数次,也就是说一个骑士其实是可以开多次会议的,所以一共可以开会的人也未必是奇数。

求出相互并不憎恨的骑士的关系图,也就是相连的骑士可以挨着。这样如果有一个奇数圈就可以确定一圈的人全部可以参加会议。

性质:如果一个双连通分量内的某些顶点在一个奇圈中(即双连通分量含有奇圈),那么这个双连通分量的其他顶点也在某个奇圈中

又知道二分图染色可以判断奇数圈,所以对每个点的强连通分量求二分图染色就ok了。这题的关键在于求点的双连通分量。

/*********************************************
Memory: 4752 KB		Time: 1141 MS
Language: G++		Result: Accepted
*********************************************/
#include <iostream>
#include <cstdio>
#include <cstring>
#define pk puts("kkk");
using namespace std;

const int N = 1005;
const int M = N * N;

struct Edge {
    int to, next;
} edge[M];
int head[N];
int cnt_edge;
void add_edge(int u, int v)
{
    edge[cnt_edge].to = v;
    edge[cnt_edge].next = head[u];
    head[u] = cnt_edge++;

    edge[cnt_edge].to = u;
    edge[cnt_edge].next = head[v];
    head[v] = cnt_edge++;
}

int dfn[N], low[N], idx;
int stk[N], top;
int kind[N], cnt;
bool ok[N], in[N];

int color[N];

int mp[N][N];
int n;

bool dfs_color(int u, int c)
{
    color[u] = c;
    for (int i = head[u]; i != -1; i = edge[i].next)
    {
        int v = edge[i].to;
        if (in[v])
        {
            if (!color[v] && !dfs_color(v, 3 - c)) return false;
            else if (color[v] == color[u]) return false;
        }
    }
    return true;
}

void dfs(int u, int pre)
{
    dfn[u] = low[u] = ++idx;
    stk[++top] = u;
    for (int i = head[u]; i != -1; i = edge[i].next)
    {
        int v = edge[i].to;
        if (v == pre) continue;
        if (!dfn[v])
        {
            dfs(v, u);
            low[u] = min(low[u], low[v]);
            if (low[v] >= dfn[u]) // u是割点, 求双连通分量
            {
                memset(in, 0, sizeof in);
                memset(color, 0, sizeof color);
                cnt = 0;
                int x;
                int num = 0;
                do {
                    x = stk[top--];
                    kind[cnt++] = x;
                    in[x] = true;
                    num++;
                } while (x != v);
                if (num <= 1) continue;
                in[u] = true;
                if (!dfs_color(u, 1))
                {
                    ok[u] = true;
                    while (cnt--) { ok[ kind[cnt] ] = true;}
                }
            }
        }
        else low[u] = min(low[u], dfn[v]);
    }
}

void solve()
{
    int ans = 0;
    for (int i = 1; i <= n; ++i) dfs(i, -1);
    for (int i = 1; i <= n; ++i) if (ok[i]) ans++;
    printf("%d\n", n - ans);
}

void init()
{
    memset(head, -1, sizeof head);
    memset(dfn, 0, sizeof dfn);
    memset(ok, 0, sizeof ok);
    memset(mp, 0, sizeof mp);
    cnt_edge = top = idx = 0;
}

int main()
{
    int m;
    int u, v;
    while (~scanf("%d%d", &n, &m))
    {
        if (n == 0 && m == 0) break;
        init();
        for (int i = 1; i <= m; ++i)
        {
            scanf("%d%d", &u, &v);
            mp[u][v] = mp[v][u] = 1;
        }
        for (int i = 1; i <= n; ++i)
            for (int j = 1; j <= n; ++j)
                if (i != j && !mp[i][j]) add_edge(i, j);
        solve();
    }

    return 0;
}

  

posted @ 2015-11-30 18:33  我不吃饼干呀  阅读(374)  评论(0编辑  收藏  举报