1. 程式人生 > >poj 2942 Knights of the Round Table(點雙連通分量+奇圈判定)

poj 2942 Knights of the Round Table(點雙連通分量+奇圈判定)

cst 一個 log ini ins cut insert bool ring

鏈接: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(點雙連通分量+奇圈判定)