poj 2942——Knights of the Round Table

来源:互联网 发布:离线运行unity3d游戏 编辑:程序博客网 时间:2024/06/05 02:07

tarjan求双连通分量+建反边+二分图判断奇偶环+交叉染色法判断该双连通分量是否为二分图

代码是写出来了,原理还需掌握

#include<iostream>#include<cstdio>#include<cstring>using namespace std;#define maxn 2100#define maxm 3100000int n,m;int map[maxn][maxn];int head[maxn],v[maxm],next[maxm],cnt;int low[maxn],dfn[maxn],step;int sta[maxn],top;bool mark[maxn];int odd[maxn];int color[maxn];void init(){memset(map,0,sizeof(map));memset(head,-1,sizeof(head));memset(low,0,sizeof(low));memset(dfn,0,sizeof(dfn));memset(odd,0,sizeof(odd));cnt=step=top=0;}void add(int x,int y){v[cnt]=y;next[cnt]=head[x];head[x]=cnt++;}bool find(int u){for(int i=head[u];~i;i=next[i]){int to=v[i];if(mark[to]){if(color[to]==-1){color[to]=(color[u]+1)%2;if(find(to))return 1;}elseif(color[to]==color[u])return 1;}}return 0;} void judge(int u){memset(color,-1,sizeof(color));color[u]=0;if(find(u))//判断这个联通图是否有奇环 for(int i=1;i<=n;i++) if(mark[i])odd[i]=1;}void tarjan(int u,int pre)  {      low[u]=dfn[u]=++step;      sta[++top]=u;      for(int i=head[u];~i;i=next[i])      {          int to=v[i];        if(!dfn[to])        {              tarjan(to,u);              low[u]=min(low[u],low[to]);              if(low[to]==dfn[u])    {      memset(mark,0,sizeof(mark));        int x;        int k=1;        mark[u]=1;        do          {              x=sta[top--];            mark[x]=1;            k++;        }while(to!=x);        if(k>=3)        judge(to);    }          }          elselow[u]=min(low[u],dfn[to]);    } } int main(){int a,b;while(~scanf("%d%d",&n,&m)&&n+m){init();for(int i=1;i<=m;i++){scanf("%d%d",&a,&b);map[a][b]=map[b][a]=1;}for(int i=1;i<=n;i++)for(int j=i+1;j<=n;j++)if(!map[i][j]){add(i,j);add(j,i);}for(int i=1;i<=n;i++)              if(!dfn[i])                tarjan(i,-1);  int ans=n;  for(int i=1;i<=n;i++)  if(odd[i])  ans--;printf("%d\n",ans);}return 0;}