題目連接c++
題意及題解參見lrj訓練指南spa
#include<bits/stdc++.h> using namespace std; const int maxn=1e3+5; int n,m; int dfn[maxn],low[maxn],time_tag; int bccno[maxn],bcc_cnt; int iscut[maxn]; int A[maxn][maxn]; vector<int> adj[maxn]; vector<int> bcc[maxn]; int odd[maxn]; struct Edge { int u,v; Edge() {} Edge(int u_,int v_) { u=u_,v=v_; } }; stack<Edge> st; void init() { memset(A,0,sizeof(A)); memset(dfn,0,sizeof(dfn)); memset(iscut,0,sizeof(iscut)); memset(bccno,0,sizeof(bccno)); memset(odd,0,sizeof(odd)); for(int i=0; i<=n; i++) adj[i].clear(),bcc[i].clear(); bcc_cnt=time_tag=0; } void dfs(int u,int pre) { low[u]=dfn[u]=++time_tag; int child=0; //子節點數目 for(int v:adj[u]) { if(v==pre) continue; if(!dfn[v]) // 把dfn[]當vis[]使用 { st.push(Edge(u,v)); child++; dfs(v,u); low[u]=min(low[u],low[v]); if(low[v]>=dfn[u]) { iscut[u]=1; bcc_cnt++; while(1) { Edge x=st.top();st.pop(); if(bccno[x.u]!=bcc_cnt) bcc[bcc_cnt].push_back(x.u),bccno[x.u]=bcc_cnt; if(bccno[x.v]!=bcc_cnt) bcc[bcc_cnt].push_back(x.v),bccno[x.v]=bcc_cnt; if(x.u==u&&x.v==v) break; } } } else if(dfn[v]<dfn[u]) { st.push(Edge(u,v)); low[u]=min(low[u],dfn[v]); } } if(pre<0&&child==1) iscut[u]=0; //只有一個孩子的根節點 } void find_bcc() { for(int i=0;i<n;i++) if(!dfn[i]) dfs(i,-1); } int color[maxn]; //斷定結點u所在的連通份量是否爲二分圖 bool bipartite(int u,int tag) { for(int v:adj[u]) { if(bccno[v]!=tag) continue; if(color[v]==color[u]) return false; if(!color[v]) { color[v]=3-color[u]; if(!bipartite(v,tag)) return false; } } return true; } int main() { while(scanf("%d%d",&n,&m)>0&&n) { init(); for(int i=0;i<m;i++) { int u,v; scanf("%d%d",&u,&v); u--,v--; A[u][v]=A[v][u]=1; } for(int u=0;u<n;u++) for(int v=u+1;v<n;v++) if(!A[u][v]) adj[u].push_back(v),adj[v].push_back(u); find_bcc(); for(int i=1;i<=bcc_cnt;i++) { memset(color,0,sizeof(color)); for(int u:bcc[i]) bccno[u]=i; int u=bcc[i][0]; color[u]=1; if(!bipartite(u,i)) for(int v:bcc[i]) odd[v]=1; } int ans=n; for(int i=0;i<n;i++) if(odd[i]) ans--; printf("%d\n",ans); } }