POJ2942 Knights of the Round Table(点双连通分量 + 二分图染色)

题目大概说要让n个骑士坐成一圈,这一圈的人数要是奇数且大于2,此外有些骑士之间有仇恨不能坐在一起,问有多少个骑士不能入座。

双连通图上任意两点间都有两条不重复点的路径,即一个环。那么,把骑士看做点,相互不仇恨的骑士间连边,能坐在一圈骑士的肯定在同一个点双连通分量上。

不过还有个条件是人数要大于2:

  • 有这么一个结论:如果一个双连通分量存在奇圈(点数为奇数的环),那么这个双连通分量里所有点一定会包含在某一个奇圈内。
  • 大概是因为,双连通分量里面点为奇数个显然都包含在奇圈里;而如果是偶数个,一部分就包含在那个找到的奇圈,而剩下的偶数-奇数=奇数个点一定也形成一个奇圈。
  • 这样只要判断双连通分量是否存在奇圈即可。而存在奇圈是图是否为二分图的充分必要条件,而判断是否为二分图可以用染色法。

因此这题就是找双连通分量,找到一个双连通分量后,染色判断它是否包含奇圈,如果是双连通分量内所有点都能入座。

要注意的是一个点能属于多个点双连通分量。

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 using namespace std;
  5 #define MAXN 1111
  6 #define MAXM 1111111
  7 struct Edge{
  8     int v,flag,next;
  9 }edge[MAXM<<1];
 10 int NE,head[MAXN];
 11 void addEdge(int u,int v){
 12     edge[NE].v=v; edge[NE].flag=0;
 13     edge[NE].next=head[u]; head[u]=NE++;
 14 }
 15 
 16 int n,ans[MAXN];
 17 
 18 int dn,dfn[MAXN],low[MAXN];
 19 int stack[MAXM],top;
 20 int tag[MAXN],color[MAXN];
 21 
 22 bool dfs(int u){
 23     for(int i=head[u]; i!=-1; i=edge[i].next){
 24         int v=edge[i].v;
 25         if(!tag[v]) continue;
 26         if(color[v]==color[u]) return 1;
 27         if(color[v]==-1){
 28             color[v]=!color[u];
 29             return dfs(v);
 30         }
 31     }
 32     return 0;
 33 }
 34 
 35 void tarjan(int u){
 36     dfn[u]=low[u]=++dn;
 37     for(int i=head[u]; i!=-1; i=edge[i].next){
 38         if(edge[i].flag) continue;
 39         edge[i].flag=edge[i^1].flag=1;
 40         stack[++top]=i;
 41 
 42         int v=edge[i].v;
 43 
 44         if(dfn[v]){
 45             low[u]=min(low[u],dfn[v]);
 46             continue;
 47         }
 48 
 49         tarjan(v);
 50         low[u]=min(low[u],low[v]);
 51 
 52         if(low[v]>=dfn[u]){
 53             memset(tag,0,sizeof(tag));
 54             int k;
 55             do{
 56                 k=stack[top--];
 57                 tag[edge[k].v]=1;
 58                 tag[edge[k^1].v]=1;
 59             }while(edge[k^1].v!=u);
 60             memset(color,-1,sizeof(color));
 61             color[u]=0;
 62             if(dfs(u)){
 63                 for(int i=1; i<=n; ++i){
 64                     if(tag[i]) ans[i]=1;
 65                 }
 66             }
 67         }
 68     }
 69 }
 70 
 71 bool ishate[MAXN][MAXN];
 72 int main(){
 73     int m;
 74     while(~scanf("%d%d",&n,&m) && (n||m)){
 75         memset(ishate,0,sizeof(ishate));
 76         int a,b;
 77         while(m--){
 78             scanf("%d%d",&a,&b);
 79             ishate[a][b]=ishate[b][a]=1;
 80         }
 81 
 82         NE=0;
 83         memset(head,-1,sizeof(head));
 84         for(int i=1; i<=n; ++i){
 85             for(int j=i+1; j<=n; ++j){
 86                 if(i==j) continue;
 87                 if(!ishate[i][j]){
 88                     addEdge(i,j);
 89                     addEdge(j,i);
 90                 }
 91             }
 92         }
 93 
 94         memset(ans,0,sizeof(ans));
 95         dn=0; memset(dfn,0,sizeof(dfn));
 96         top=0;
 97         for(int i=1; i<=n; ++i){
 98             if(dfn[i]==0) tarjan(i);
 99         }
100 
101         int res=0;
102         for(int i=1; i<=n; ++i){
103             if(!ans[i]) ++res;
104         }
105         printf("%d
",res);
106     }
107     return 0;
108 }
原文地址:https://www.cnblogs.com/WABoss/p/5694413.html