poj 2942 Knights of the Round Table(点双连通分量+奇圈判定)
Posted 7391_KID
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了poj 2942 Knights of the Round Table(点双连通分量+奇圈判定)相关的知识,希望对你有一定的参考价值。
链接:https://vjudge.net/problem/POJ-2942
题意:给定一个无向图,求出补图,然后求补图中有多少个点不属于任何奇圈。
分析:首先是骑士有不能坐在一起的人,不好想,反过来想,相当于和其他人可以坐在一起,连一条边,围成一圈就变成了该点是否在某个点双连通分量里,所以先用Tarjan算法处理出所有的点双连通分量。然后还有一个要求,该点得在某个含奇数个点的点双连通分量里。
首先点双连通分量有两个性质:1.如果该分量里有一个奇圈,那么其他所有点也必然在某个奇圈中;2.含有一个奇圈的充要条件是该分量不是二分图。
- - 知道了这些性质就好做点了。。处理完点双连通分量以后,对每个分量都用染色法判断是否是二分图,如果是二分图,那么这些人不能坐在一起开会,否则每个点都标记一下,等处理完所有分量后统计下没被标记的点数,就是答案。注意当分量中只有两个点时,虽然是二分图,但是也不满足条件。
是道好题。。但wa了9发才过。。主要是Tarjan的模板出错了没找到。。
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<stack> 5 #include<vector> 6 #include<set> 7 using namespace std; 8 const int maxn=1005; 9 int dfn[maxn],low[maxn],fa[maxn],cnt=0,bcc_cnt=0; 10 int n,m; 11 bool vis[maxn],Is_cut[maxn]; 12 struct Edge{ 13 int u,v; 14 Edge(int _u,int _v):u(_u),v(_v){} 15 }; 16 vector<Edge> edges; 17 vector<int>G[maxn]; 18 set<int>bcc[maxn]; 19 int g[maxn][maxn]; 20 stack<int>sta; 21 void AddEdge(int u,int v){ 22 edges.push_back(Edge(u,v)); 23 edges.push_back(Edge(v,u)); 24 G[u].push_back(edges.size()-2); 25 G[v].push_back(edges.size()-1); 26 } 27 void dfs(int u){ 28 if(vis[u])return ; 29 vis[u]=true; 30 dfn[u]=cnt++; 31 low[u]=dfn[u]; 32 int child=0; 33 for(int i=0;i<G[u].size();i++){ 34 int v=edges[G[u][i]].v; 35 if(!vis[v]){ 36 sta.push(G[u][i]); 37 fa[v]=u; 38 child++; 39 dfs(v); 40 low[u]=min(low[u],low[v]); 41 if(low[v]>=dfn[u]){ 42 Is_cut[u]=true; 43 bcc[bcc_cnt].clear(); 44 while(1){ 45 Edge e=edges[sta.top()];sta.pop(); 46 bcc[bcc_cnt].insert(e.u); 47 bcc[bcc_cnt].insert(e.v); 48 if(e.u==u&&e.v==v)break; 49 } 50 bcc_cnt++; 51 } 52 }else if(dfn[v]<dfn[u]&&v!=fa[u]){ 53 sta.push(G[u][i]); 54 low[u]=min(low[u],dfn[v]); 55 } 56 } 57 if(fa[u]==-1&&child<=1)Is_cut[u]=false; 58 } 59 void Tarjan(){ 60 memset(vis,0,sizeof(vis)); 61 memset(Is_cut,0,sizeof(Is_cut)); 62 for(int i=1;i<=n;i++){ 63 if(!vis[i]){ 64 fa[i]=-1; 65 dfs(i); 66 } 67 } 68 } 69 70 bool ok[maxn]; 71 int color[maxn]; 72 void init(){ 73 edges.clear(); 74 for(int i=1;i<=n;i++)G[i].clear(); 75 cnt=bcc_cnt=0; 76 while(!sta.empty())sta.pop(); 77 memset(ok,0,sizeof(ok)); 78 for(int i=1;i<=n;i++){ 79 for(int j=1;j<=n;j++)g[i][j]=1; 80 g[i][i]=0; 81 } 82 } 83 bool Is_btg(set<int> &S){ 84 memset(color,0,sizeof(color)); 85 stack<int> s; 86 s.push(*S.begin()); 87 color[*S.begin()]=1; 88 while(!s.empty()){ 89 int u=s.top();s.pop(); 90 for(int i=0;i<G[u].size();i++){ 91 int v=edges[G[u][i]].v; 92 if(!S.count(v))continue; 93 if(color[v]==color[u])return false; 94 if(!color[v]){ 95 s.push(v); 96 color[v]=-color[u]; 97 } 98 } 99 } 100 return true; 101 } 102 int main(){ 103 // freopen("e:\\in.txt","r",stdin); 104 while(scanf("%d%d",&n,&m)!=EOF&&(n+m)){ 105 init(); 106 int u,v; 107 for(int i=0;i<m;i++){ 108 scanf("%d%d",&u,&v); 109 g[u][v]=0;g[v][u]=0; 110 } 111 for(int i=1;i<=n;i++){ 112 for(int j=i+1;j<=n;j++) 113 if(g[i][j])AddEdge(i,j); 114 } 115 // for(int i=1;i<=n;i++){ 116 // for(int j=0;j<G[i].size();j++){ 117 // cout<<G[i][j]<<‘ ‘; 118 // } 119 // cout<<endl; 120 // } 121 Tarjan(); 122 // for(int i=0;i<bcc_cnt;i++){ 123 // for(set<int>::iterator it=bcc[i].begin();it!=bcc[i].end();it++){ 124 // cout<<*it<<‘ ‘; 125 // } 126 // cout<<endl; 127 // } 128 for(int i=0;i<bcc_cnt;i++){ 129 int len=bcc[i].size(); 130 if(len>2&&!Is_btg(bcc[i])){ 131 for(set<int>::iterator it=bcc[i].begin();it!=bcc[i].end();it++) 132 ok[*it]=true; 133 } 134 } 135 int ans=0; 136 for(int i=1;i<=n;i++) 137 if(!ok[i])ans++; 138 printf("%d\n",ans); 139 140 } 141 return 0; 142 }
以上是关于poj 2942 Knights of the Round Table(点双连通分量+奇圈判定)的主要内容,如果未能解决你的问题,请参考以下文章
poj2942 Knights of the Round Table
poj2942:Knights of the Round Table——题解
poj2942 Knights of the Round Table
POJ 2942Knights of the Round Table(二分图判定+双连通分量)