大致题意:
给出一个无向图,求出这个图的补图G。求出在G中存在多少个点使得这些点不属于任何一个奇环中。
大致思路:
这道题从一开始就是个杯具!先是把题目想成边的双连通分量做,狂哇。后来用割点的模版照着网上的代码改造出一个点双连通分量的代码,依然哇!!原因是同一个点可能属于不同的点双连通分量!! 后来把搜索染色的过程加到Tarjan里面,还是哇!!检查出来原因是搜索u的时候,起点并没有标记其在那一块双连通分量!! 前前后后花了我八天才AC……大概得终身难忘这道题了>_< 发图供大牛BS
给出一组可以判边双连通分量死刑的数据
#include<iostream> #include<cstdio> #include <algorithm> #include<cstring> using namespace std; const int inf=1<<30; const int nMax=30015; const int mMax=5000000; class edge{ public: int u,v,nex; };edge e[mMax]; int k,k1,head[nMax];//head[i]是以点i为起点的链表头部 int dfn[nMax],low[nMax],sta[nMax],top,atype,belon[nMax],dep; //Tarjan需要的数据记录 //atype 强连通分量的个数 bool insta[nMax]; int n,m; int ans,vis[nMax],num[nMax]; void addedge(int a,int b){ e[k].u=a; e[k].v=b; e[k].nex=head[a]; head[a]=k;k++; } int change(int a){ if(a==1)return 2; if(a==2)return 1; return 0; } int clor[nMax],cnt; bool dfs(int loc,int val){ int i,v; clor[loc]=val; for(i=head[loc];i;i=e[i].nex){ v=e[i].v; if(atype!=belon[v])continue; if(clor[v]==0){ if(!dfs(v,change(val))){ return 0; } } else{ if(clor[v]!=change(clor[loc])){ return 0; } } } return 1; } void Tarjan(int u,int rt){ //我的Tarjan模版 int i,t; dfn[u]=low[u]=++dep; sta[++top]=u; insta[u]=1; for(i=head[u];i;i=e[i].nex){ int v=e[i].v; if(v==rt)continue; if(!dfn[v]){ Tarjan(v,u); low[u]=min(low[u],low[v]); if(dfn[u]<=low[v]){ ///要注意一个点可能同时属于不同的点双连通分量 atype++; //点双通分量个数 do{ t=sta[top--]; insta[t]=0; belon[t]=atype; //第j个点属于第atype个连通块 num[++cnt]=t; }while(v!=t); num[++cnt]=u; memset(clor,0,sizeof(clor)); if(cnt>=3&&!dfs(u,1)){ while(cnt>0) vis[num[cnt--]]=1; } else cnt=0; } } else{ if(insta[v])low[u]=min(low[u],dfn[v]); } } } void init(){ k=k1=1; dep=1; top=atype=0; memset(insta,0,sizeof(insta)); //是否在栈中 memset(head,0,sizeof(head)); //静态链表头指针 memset(low,0,sizeof(low)); //Tarjan的low数组 memset(dfn,0,sizeof(dfn)); //Tarjan的dfn数组 memset(belon,0,sizeof(belon)); //记录每个点属于哪一个双连通分量 } bool map[2000][2000]; int main(){ int i,j,a,b; while(scanf("%d%d",&n,&m)!=EOF&&(n||m)){ init(); ans=0; cnt=0; memset(map,0,sizeof(map)); while(m--){ scanf("%d%d",&a,&b); map[a][b]=map[b][a]=1; } for(i=1;i<=n;i++){ for(j=1;j<=n;j++){ if(!map[i][j]&&i!=j){ addedge(i,j); } } } memset(vis,0,sizeof(vis)); for(i=1;i<=n;i++){ if(!dfn[i])Tarjan(i,-1); } for(i=1;i<=n;i++){ if(!vis[i])ans++; } printf("%d\n",ans); } return 0; }