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\n",ret);
155     }      
156     return 0;
157 }
View Code

 

 

 

posted @ 2014-02-17 15:09  N_ll  阅读(265)  评论(0编辑  收藏  举报