「POJ2942」Knights of the Round Table
把能坐在一起的连边,求出点双连通分量,再对每个点双连通分量判一下是否存在奇环。
1 #include<cstdio> 2 #include<iostream> 3 #include<vector> 4 #include<queue> 5 #include<cstring> 6 using namespace std; 7 const int N=1010,M=1000010; 8 int n,m,color[N]; 9 bool hate[N][N],can[N]; 10 int dfn[N],low[N],timer,cnt,sta[N],top; 11 vector<int>tog[N]; 12 void tarjan(int k,int fa){ 13 dfn[k]=low[k]=++timer; 14 sta[top++]=k; 15 for(int i=1;i<=n;i++)if(!hate[k][i]){ 16 if(fa==i) continue; 17 if(!dfn[i]){ 18 tarjan(i,k); 19 low[k]=min(low[k],low[i]); 20 if(dfn[k]<=low[i]){ 21 cnt++; 22 while(sta[top]!=i) top--,tog[cnt].push_back(sta[top]);; 23 tog[cnt].push_back(k); 24 } 25 }else if(dfn[k]>dfn[i]) low[k]=min(low[k],dfn[i]); 26 } 27 if(!fa){ 28 cnt++; 29 while(top){top--;tog[cnt].push_back(sta[top]);} 30 } 31 return; 32 } 33 inline bool pd(int k,int x){ 34 for(int i=0;i<tog[k].size();i++) if(tog[k][i]==x)return 1; 35 return 0; 36 } 37 bool check(int k){ 38 if(tog[k].size()==1) return 0; 39 memset(color,0,sizeof(color)); 40 queue<int>q; 41 q.push(tog[k][0]); 42 color[tog[k][0]]=1; 43 int now; 44 while(!q.empty()){ 45 now=q.front();q.pop(); 46 for(int i=1;i<=n;i++) if(!hate[now][i]&&pd(k,i)){ 47 if(!color[i]){ 48 color[i]=-1*color[now]; 49 q.push(i); 50 }else if(color[i]==color[now]) return 1; 51 } 52 } 53 return 0; 54 } 55 inline void reset(){ 56 for(int i=1;i<=cnt;i++) tog[i].clear(); 57 memset(dfn,0,sizeof(dfn)); 58 memset(low,0,sizeof(low)); 59 memset(hate,0,sizeof(hate)); 60 memset(can,0,sizeof(can)); 61 cnt=timer=0; 62 return; 63 } 64 void solve(){ 65 if(!n) exit(0); 66 int t1,t2,ans=0; 67 for(int i=1;i<=m;i++) scanf("%d%d",&t1,&t2),hate[t1][t2]=hate[t2][t1]=1; 68 for(int i=1;i<=n;i++) hate[i][i]=1; 69 for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i,0); 70 for(int i=1;i<=cnt;i++) if(check(i)) 71 for(int j=0;j<tog[i].size();j++) can[tog[i][j]]=1; 72 for(int i=1;i<=n;i++) if(!can[i]) ans++; 73 printf("%d\n",ans); 74 reset(); 75 return; 76 } 77 int main(){ 78 while(scanf("%d%d",&n,&m)) solve(); 79 return 0; 80 }