POJ 2942 Knights of the Round Table 补图+tarjan求点双联通分量+二分图染色+debug

题面还好,就不描述了


重点说题解:

由于仇恨关系不好处理,所以可以搞补图存不仇恨关系,

如果一个桌子上面的人能坐到一起,显然他们满足能构成一个环

所以跑点双联通分量

求点双联通分量我用的是向栈中push边的方法

请注意:只向栈中push树枝边

这样每次一对父子(u,v)

如果low[v]<=dfn[u] 显然u是v所在点双联通分量的割点

所以栈中边(u,v)之前的边都pop,他们连接的点构成点双联通分量

我们找到一个点双联通分量之后,由于要求奇数个人坐一桌

所以满足存在奇环,dfs染色即可

注意割点可能属于很多点双联通分量,所以染完色之后需要给他把颜色去掉

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<cstring>
  4 #include<vector>
  5 #include<stack>
  6 #define N 1010
  7 using namespace std;
  8 int n,m,head[N],adj[N][N],ans,dfn[N],low[N],ok[N],ecnt,indx,clr[N],inst[N];
  9 int read()
 10 {
 11     int ret=0,neg=1;
 12     char j=getchar();
 13     for (;j<'0' || j>'9';j=getchar())
 14     if (j=='-') neg=-1;
 15     for (;j<='9' && j>='0';j=getchar())
 16     ret=ret*10+j-'0';
 17     return ret*neg;
 18 }
 19 struct edge
 20 {
 21     int u,v,nxt;
 22 }e[N*N];
 23 stack <edge> stk;
 24 stack <int> tmp;
 25 void add(int u,int v)
 26 {
 27     e[++ecnt].u=u;
 28     e[ecnt].v=v;
 29     e[ecnt].nxt=head[u];
 30     head[u]=ecnt;
 31 }
 32 void getG()//还是推荐链式前向星存图= =
 33 {
 34     for (int i=1,u,v;i<=m;i++)
 35     {
 36     u=read(),v=read();
 37     adj[u][v]=1;
 38     adj[v][u]=1;
 39     }
 40     for (int i=1;i<=n;i++)
 41     for (int j=1;j<=n;j++)
 42         if (adj[i][j]==0 && i!=j) add(i,j);
 43 }
 44 int dfs(int u,int nw)//染色
 45 {
 46     int ret=1;
 47     for (int i=head[u];i;i=e[i].nxt)
 48     {
 49     int v=e[i].v;
 50     if (inst[v]==1)
 51     {
 52         if (clr[v]==-1)
 53         {
 54         clr[v]=1-nw;
 55         ret&=dfs(v,1-nw);
 56         }
 57         else
 58         if (clr[v]==nw) ret=0;
 59     }
 60     }
 61     return ret;
 62 }
 63 void init()
 64 {
 65     memset(ok,0,sizeof(ok));
 66     memset(head,0,sizeof(head));
 67     memset(adj,0,sizeof(adj));
 68     memset(inst,0,sizeof(inst));
 69     ecnt=1;
 70     memset(dfn,0,sizeof(dfn));
 71     memset(clr,-1,sizeof(clr));
 72     indx=0;
 73     ans=0;
 74 }
 75 void tar(int u,int fa)
 76 {
 77     dfn[u]=low[u]=++indx;
 78     for (int i=head[u];i;i=e[i].nxt)
 79     {
 80     int v=e[i].v;
 81     if (!dfn[v])
 82     {
 83         stk.push(e[i]);
 84         tar(v,u);
 85         low[u]=min(low[u],low[v]);
 86         if (low[v]>=dfn[u])//题解找双联通分量部分
 87         {
 88         while (1)
 89         {
 90             edge e=stk.top();
 91             stk.pop();
 92             inst[e.u]=1;
 93             inst[e.v]=1;
 94             tmp.push(e.u);
 95             tmp.push(e.v);
 96             if (e.u==u && e.v==v) break;
 97         }
 98         clr[u]=1;
 99         if (dfs(u,1)==0)
100             while (!tmp.empty())
101             {
102             ok[tmp.top()]=1;
103             inst[tmp.top()]=0;
104             tmp.pop();
105             }
106         else while (!tmp.empty()) inst[tmp.top()]=0,tmp.pop();
107         clr[u]=-1;
108         }
109     }
110     else if (v!=fa)
111         low[u]=min(low[u],dfn[v]);
112     }
113 }
114 int main()
115 {
116     n=read();
117     m=read();
118     while (n || m)
119     {
120     init();
121     getG();
122     for (int i=1;i<=n;i++)
123         if (!dfn[i]) tar(i,-1);
124     for (int i=1;i<=n;i++)
125         ans+=ok[i];
126     printf("%d
",n-ans);
127     n=read(),m=read();
128     }
129     return 0;
130 }
原文地址:https://www.cnblogs.com/mrsheep/p/7852160.html