灰书例题,用染色判断二分图在点双联通分量找奇圈。
写错了几次,返祖边不能入栈。
======
题目建模利用补图,因为是圆桌,所以人在奇环上。
其实返祖边可以入栈,我自己没判(DFN[i]<DFN[u])才萎掉的。
======
再梳理一下。
首先在有向图中Tarjan向下(if(!DFN[i]){)是从树边走,向上更新Low是沿着后向边(else{Low[u]=min(DFN[i],Low[u]);},前向边(DFN[i]<DFN[u])是要排除的。
我在else里一开始写了入栈和更新Low没排除前向边就错了。但是索性去掉入栈就AC了,是因为先前向边一定不会更新Low数组,(DFN[i]>DFN[u]>Low[u])。
想想应该还是把那个判断(DFN[i]<DFN[u])写上比较好。
Code #include <iostream> #include <cstring> #include <vector> #include <stack> #define PII make_pair using namespace std; const int maxn=1000+10,maxm=1000000+10; bool G[maxn][maxn],ok[maxn]; int n,m,DFN[maxn],Low[maxn],belong[maxn],Index,cnt; vector<int> BCC[maxn]; stack< pair<int,int> > s; void Tarjan(int u,int fa) { DFN[u]=Low[u]=++Index; for(int i=1;i<=n;i++) if(i!=fa && G[u][i] && i!=u){ if(!DFN[i]){ s.push(PII(u,i)); Tarjan(i,u); Low[u]=min(Low[i],Low[u]); if(DFN[u]<=Low[i]){ BCC[++cnt].clear(); pair<int,int> e; do{ e=s.top();s.pop(); if(belong[e.first ]!=cnt){belong[e.first ]=cnt;BCC[cnt].push_back(e.first );} if(belong[e.second]!=cnt){belong[e.second]=cnt;BCC[cnt].push_back(e.second);} }while((e.first!=u)||(e.second!=i)); } } else Low[u]=min(DFN[i],Low[u]); } } bool color(int u) { for(int i=1;i<=n;i++){ if((!G[u][i])||(belong[u]!=belong[i])||(i==u))continue; if(DFN[i]==DFN[u])return 0; if(!DFN[i]){ DFN[i]=3-DFN[u]; if(!color(i))return 0; } } return 1; } int main() { ios::sync_with_stdio(0); while(cin>>n>>m){ if(n==0 && m==0)break; memset(G,1,sizeof(G)); for(int i=0;i<m;i++){ int x,y; cin>>x>>y; G[x][y]=G[y][x]=0; } memset(ok,0,sizeof(ok)); memset(DFN,0,sizeof(DFN)); memset(Low,0,sizeof(Low)); memset(belong,0,sizeof(belong)); Index=0;cnt=0; for(int i=1;i<=n;i++) if(!DFN[i]) Tarjan(i,0); for(int i=1;i<=cnt;i++){ memset(DFN,0,sizeof(DFN)); for(int j=0;j<BCC[i].size();j++) belong[BCC[i][j]]=i; DFN[BCC[i][0]]=1; if(!color(BCC[i][0])) for(int j=0;j<BCC[i].size();j++)ok[BCC[i][j]]=1; } int ans=0; for(int i=1;i<=n;i++)ans+=ok[i]; cout<<n-ans<<endl; } return 0; }
一个萎掉的例子,处理一条返祖边祖先节点时会把一个已经在某一个BCC里孩子加到当前BCC,就是说只要返祖边向上的方向,不能要返祖边向下的方向。
Code 6 8 1 4 1 5 1 6 2 4 2 5 2 6 3 6 4 5 //WA try1->2 push1,2 try2->3 push2,3 try3->1 push3,1 try3->4 push3,4 try4->6 push4,6 try6->5 push6,5 try5->3 push5,3 pop5,3 pop6,5 pop4,6 pop3,4 try3->5 push3,5 pop3,5 pop3,1 pop2,3 pop1,2 try1->3 push1,3 belong:1,5 belong:1,3 belong:1,6 belong:1,4 belong:2,3 belong:2,5 belong:2,1 belong:2,2 2 //AC try1->2 push1,2 try2->3 push2,3 try3->1 push3,1 try3->4 push3,4 try4->6 push4,6 try6->5 push6,5 try5->3 push5,3 pop5,3 pop6,5 pop4,6 pop3,4 try3->5 pop3,1 pop2,3 pop1,2 try1->3 belong:1,5 belong:1,3 belong:1,6 belong:1,4 belong:2,3 belong:2,1 belong:2,2 3