zoukankan      html  css  js  c++  java
  • 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 - 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;
    }
    

      

  • 相关阅读:
    TCP四次握手断开连接(十一)
    Go-函数
    Go-数据类型以及变量,常量
    GO语言介绍以及开发环境配置
    Socket与WebSocket以及http与https重新总结
    希尔排序
    第19课
    第18课
    外传篇3 动态内存申请的结果
    外传篇2 函数的异常规格说明
  • 原文地址:https://www.cnblogs.com/wenruo/p/5008032.html
Copyright © 2011-2022 走看看