双连通分量Tarjan+交叉染色
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
struct edge
{
int u;
int v;
};
int n;
int g[1010][1010];
int tg[1010][1010],lt[1010];
bool flag[1010];
int dfn[1010],low[1010];
int mv[1010];
int ls,tag,lv;
edge s[1010];
int color[1010];
int mem[1010];
bool dfs(int u,int lc)
{
int i,v;
bool t;
color[u]=lc;
for (i=0; i<lt[u]; i++)
{
v=tg[u][i];
if (flag[v] == true && color[v] == 0)
{
color[v]=tag;
t=dfs(v,-lc);
if (t == true)
return true;
}
else if (flag[v] == true && color[v] == lc)
{
return true;
}
}
return false;
}
bool check(int u)
{
memset(color,0,sizeof(color));
if (dfs(u,1) == true)
return true;
return false;
}
void tarjan(int u,int pr)
{
int i,v,j;
edge te;
dfn[u]=tag;
low[u]=tag;
tag++;
for (i=0; i<lt[u]; i++)
{
v=tg[u][i];
if (v == pr)
continue;
if (dfn[v] == -1)
{
te.u=u;
te.v=v;
s[ls]=te;
ls++;
tarjan(v,u);
if (low[v] < low[u])
low[u]=low[v];
if (low[v] >= dfn[u])
{
memset(flag,false,sizeof(flag));
lv=0;
do
{
te=s[ls-1];
ls--;
if (flag[te.u] == false)
{
mv[lv]=te.u;
lv++;
flag[te.u]=true;
}
if (flag[te.v] == false)
{
mv[lv]=te.v;
lv++;
flag[te.v]=true;
}
}while (te.u != u && te.v != v && ls > 0);
if (check(mv[0]) == true)
{
for (j=0; j<lv; j++)
{
mem[mv[j]]=true;
}
}
}
}
else
{
if (low[u] > dfn[v])
low[u]=dfn[v];
}
}
}
int main()
{
int m,t1,t2,i,j;
while (1)
{
memset(g,0,sizeof(g));
scanf("%d%d",&n,&m);
if (n == 0 && m == 0)
break;
while (m--)
{
scanf("%d%d",&t1,&t2);
g[t1][t2]=1;
g[t2][t1]=1;
}
for (i=1; i<=n; i++)
{
lt[i]=0;
for (j=1; j<=n; j++)
{
if (i == j)
continue;
if (g[i][j] == 0)
{
tg[i][lt[i]]=j;
lt[i]++;
}
}
}
memset(dfn,-1,sizeof(dfn));
memset(mem,false,sizeof(mem));
for (i=1; i<=n; i++)
{
ls=0;
tag=1;
if (dfn[i] == -1)
tarjan(i,-1);
}
m=0;
for (i=1; i<=n; i++)
{
if (mem[i] == true)
m++;
}
printf("%d\n",n-m);
}
}