圆桌骑士

链接: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; 
}
原文地址:https://www.cnblogs.com/yinwuxiao/p/8835577.html