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 }