• Knights of the Round Table(Tarjan+奇圈)


    http://poj.org/problem?id=2942

    题意:n个武士,某些武士之间相互仇视,如果在一起容易发生争斗事件。所以他们只有满足一定的条件才能参加圆桌会议:(1)相互仇视的两个武士不能相邻 (2)同一个圆桌边上的武士数量必须是奇数。输出需要剔除的武士人数。
       /     路:根据图中的关系建立该图的补图,(Tarjan算法)求出图中的双连通分量,判断每个双连通分量中是否存在奇圈,若存在奇圈则该连通分量中的武士都符合条件,否则都不符合        |.|  判断奇圈的方法:由于二分图中不含奇圈,可判断连通分量是否为二分图,若是,则不含奇圈,否则存在奇圈。。
       |.|
       |:|   __    
      ,_|:|_,  / )
       (Oo  / _I_
       +  ||^ ^|
         ||_0→  
          /.:.-
          |.:. /-----
          |___|::oOo::|
          /  |:<_T_>:|(无意中发现的武士字符画。。哈哈)
        ""....""

      1 #include <stdio.h>
      2 #include <string.h>
      3 #include <algorithm>
      4 #include <vector>
      5 #include <stack>
      6 using namespace std;
      7 const int N=1010;
      8 struct Edge
      9 {
     10     int u,v;
     11     Edge(int u,int v):u(u),v(v) {}
     12 };
     13 int low[N],dfn[N],iscut[N],bridge[N][N];
     14 int color[N],odd[N],bccno[N],map[N][N];
     15 int dfs_clock,bcc_cnt,n,m;
     16 vector<int>G[N],bcc[N];
     17 stack<Edge>S;
     18 
     19 void init()
     20 {
     21     bcc_cnt = 0;
     22     dfs_clock = 0;
     23     while(!S.empty()) S.pop();
     24     memset(low,0,sizeof(low));
     25     memset(dfn,0,sizeof(dfn));
     26     memset(iscut,0,sizeof(iscut));
     27     memset(bridge,0,sizeof(bridge));
     28     memset(bccno,0,sizeof(bccno));
     29     memset(odd,0,sizeof(odd));
     30     memset(map,0,sizeof(map));
     31     for (int i = 0; i < N; i++)
     32     {
     33         G[i].clear();
     34         bcc[i].clear();
     35     }
     36 }
     37 void dfs(int u,int father)//Tarjan
     38 {
     39     low[u]=dfn[u]=++dfs_clock;
     40     int child = 0;
     41     for (int i = 0; i < G[u].size(); i++)
     42     {
     43         int v = G[u][i];
     44         Edge e(u,v);
     45         if (!dfn[v])
     46         {
     47             S.push(e);
     48             child++;
     49             dfs(v,u);
     50             low[u] = min(low[u],low[v]);
     51             if(dfn[u] <= low[v])
     52             {
     53                 iscut[u] = 1;//u为割点
     54                 ++bcc_cnt;
     55                 while(1)
     56                 {
     57                     Edge x = S.top();
     58                     S.pop();
     59                     if(bccno[x.u]!=bcc_cnt)
     60                     {
     61                         bccno[x.u] = bcc_cnt;//点u属于第bcc_cnt个连通分量
     62                         bcc[bcc_cnt].push_back(x.u);
     63                     }
     64                     if (bccno[x.v]!=bcc_cnt)
     65                     {
     66                         bccno[x.v] = bcc_cnt;
     67                         bcc[bcc_cnt].push_back(x.v);
     68                     }
     69                     if (x.u==u&&x.v==v)
     70                         break;
     71                 }
     72             }
     73             if (low[v] > dfn[u]) bridge[u][v] = 1;//u-v之间为桥
     74         }
     75         else if (dfn[v]<dfn[u]&&v!=father)
     76         {
     77             S.push(e);
     78             low[u] = min(low[u],dfn[v]);
     79         }
     80     }
     81     if (father<0&&child==1)
     82         iscut[u]=0;
     83 }
     84 bool bipartite(int u,int b)//判断二分图(交叉染色法)
     85 {
     86     for (int i = 0; i < G[u].size(); i++)
     87     {
     88         int v = G[u][i];
     89         if (bccno[v]!=b) continue;
     90         if (color[u]==color[v]) return false;
     91         if (!color[v])
     92         {
     93             color[v] = 3-color[u];
     94             if (!bipartite(v,b))
     95                 return false;
     96         }
     97     }
     98     return true;
     99 }
    100 int main()
    101 {
    102     while(~scanf("%d%d",&n,&m))
    103     {
    104         if (n==0&&m==0)
    105             break;
    106         int u,v;
    107         init();
    108         for (int i = 0; i < m; i++)
    109         {
    110             scanf("%d%d",&u,&v);
    111             --u;
    112             --v;
    113             map[u][v]=map[v][u]=1;
    114         }
    115         for (int i = 0; i < n; i++)
    116         {
    117             for (int j = i+1; j <n; j++)
    118             {
    119                 if (!map[i][j])
    120                 {
    121                     G[i].push_back(j);//建立无向的补图
    122                     G[j].push_back(i);
    123                 }
    124             }
    125         }
    126         for (int i = 0; i <n; i++)
    127         {
    128             if (!dfn[i])
    129                 dfs(i,-1);
    130         }
    131         for (int i = 1; i <= bcc_cnt; i++)
    132         {
    133             memset(color,0,sizeof(color));
    134             for (int j = 0; j < bcc[i].size(); j++)
    135             {
    136                 bccno[bcc[i][j]] = i;
    137             }
    138             int u = bcc[i][0];
    139             color[u] = 1;
    140             if(!bipartite(u,i))
    141             {
    142                 for (int j = 0; j < bcc[i].size(); j++)
    143                 {
    144                     odd[bcc[i][j]] =1;//标记奇圈中的点
    145                 }
    146             }
    147         }
    148         int ret = 0;
    149         for (int i = 0; i < n; i++)
    150         {
    151             if (!odd[i])
    152                 ret++;
    153         }
    154         printf("%d
    ",ret);
    155     }      
    156     return 0;
    157 }
    View Code
  • 相关阅读:
    spock2.x结合mockito静态mock
    线程池的拒绝策略及常见线程池
    正确关闭线程池
    对线面试官 | 字节跳动一面
    记一次oom问题排查
    MySQL索引下推,原来这么简单!
    vs2019 编译 protocol buffers
    每日一库:classList.js
    每日一库:tinycon.js
    算法: 有效的括号
  • 原文地址:https://www.cnblogs.com/lahblogs/p/3552627.html
Copyright © 2020-2023  润新知