tarjan求双连通分量+建反边+二分图判断奇偶环+交叉染色法判断该双连通分量是否为二分图
代码是写出来了,原理还需掌握
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define maxn 2100
#define maxm 3100000
int 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;
}
else
if(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);
}
}
else
low[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;
}
962

被折叠的 条评论
为什么被折叠?



