圆桌骑士
链接:https://vjudge.net/contest/141787#problem/A
题解:
首先可以证明出
在一个点双联通分量里,如果有奇环,那么所有点都不满足
然后就是求点双联通了
代码:
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <stack>
#include <vector>
#include <cstring>
using namespace std;
#define N 30000
stack<int> s;
int low[N],dfn[N],head[N],color[N],ff[N],now,cnt,l,n,m;
bool odd[N],iscut[N];
vector<int> bcc[N];
struct re{
int a,b,c,from;
}a[3000000];
bool p[2000][2000];
void arr(int x,int y)
{
a[++l].a=head[x];
a[l].b=y;
a[l].from=x;
head[x]=l;
}
void tarjan(int x,int fa)
{
low[x]=dfn[x]=++now;
int child=0;
int u=head[x];
while (u)
{
int v=a[u].b;
if (!dfn[v])
{
s.push(u);
child++;
tarjan(v,x);
low[x]=min(low[x],low[v]);
if (low[v]>=dfn[x])
{
iscut[x]=1;
cnt++; bcc[cnt].clear();
while (true)
{
int u=s.top(); s.pop();
int y=a[u].from;
if (ff[y]!=cnt)
{
bcc[cnt].push_back(y);
ff[y]=cnt;
}
y=a[u].b;
if (ff[y]!=cnt)
{
bcc[cnt].push_back(y);
ff[y]=cnt;
}
if (a[u].from==x&&a[u].b==v) break;
}
}
} else
if (dfn[x]>dfn[v]&&v!=fa)
s.push(u),low[x]=min(low[x],dfn[v]);
u=a[u].a;
}
if (fa<0&&child==1) iscut[x]=0;
}
bool pd(int x,int pos)
{
int u=head[x],tt=1;
while (u)
{
int v=a[u].b;
if (ff[v]==pos)
{
if (!color[v])
{
color[v]=3-color[x];
tt=tt&pd(v,pos);
}
if (color[v]!=3-color[x]) tt=0;
}
u=a[u].a;
}
return(tt);
}
int main()
{
freopen("noi.in","r",stdin);
freopen("noi.out","w",stdout);
std::ios::sync_with_stdio(false);
while (cin>>n>>m&&n)
{
l=0; memset(head,0,sizeof(head));
memset(ff,0,sizeof(ff));
memset(odd,0,sizeof(odd));
int x,y;
memset(p,0,sizeof(p));
for (int i=1;i<=m;i++)
cin>>x>>y,p[x][y]=1,p[y][x]=1;
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
if (!p[i][j]&&i!=j) arr(i,j);
/* for (int i=1;i<=l;i++)
{
cout<<a[i].from<<" "<<a[i].b<<endl;
}*/
now=0; cnt=0;
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(iscut,0,sizeof(iscut));
for (int i=1;i<=n;i++)
if (!dfn[i]) tarjan(i,0);
for (int i=1;i<=cnt;i++)
{
memset(color,0,sizeof(color));
for (int j=0;j<bcc[i].size();j++)
ff[bcc[i][j]]=i;
int x=bcc[i][0];
color[x]=1;
if (!pd(x,i))
for (int j=0;j<bcc[i].size();j++)
odd[bcc[i][j]]=1;
}
int ans=n;
for (int i=1;i<=n;i++) if (odd[i]) ans--;
cout<<ans<<endl;
}
return 0;
}