heoitys

建补图,是两个不仇恨的骑士连边,如果有环,则可以凑成一桌和谐的打麻将

不能直接缩点,因为直接缩点求的是连通分量,点双缩点只是把环缩起来

普通缩点                                                                                               点双缩点

  

由图可知,左图中的缩法不符题意,而右图两个缩完后的点都满足题意

然后题中说必须要奇数个骑士参加会议,即找奇圈(有奇数个点的圈)

问题就转化成缩点后判断一个点是否在奇圈里,这就用到了点双的性质

点双连通分量有两个性质:1.如果该分量里有一个奇圈,那么其他所有点也必然在某个奇圈中;2.含有一个奇圈的充要条件是该分量不是二分图。

所以我们只需要缩完点之后枚举V-DCC判断是不是二分图,不是二分图就是奇圈

那么判断二分图用染色法判断即可

注意一个骑士不可以参加会议

这句话是自言自语: Lockey注意要检查变量名是否写对了

二分图定义:

  一个无向图,使得顶点集V可以分割为两个互不相交的子集A,B,使得所有边两端分别属于两个子集A,B

度娘解释

 

  二分图是这样一个图: 有两顶点集且图中每条边的的两个顶点分别位于两个顶点集中,每个顶点集中没有边直接相连接!

 

  无向图G为二分图的充分必要条件是,G至少有两个顶点,且其所有回路的长度均为偶数。

 

  判断二分图的常见方法是染色法: 开始对任意一未染色的顶点染色,之后判断其相邻的顶点中,若未染色则将其染上和相邻顶点不同的颜色, 若已经染色且颜色和相邻顶点的颜 色相同则说明不是二分图,若颜色不同则继续判断,bfs和dfs可以搞定!
  易知:任何无回路的的图均是二分图
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<vector>
 4 #include<cstring>
 5 using namespace std;
 6 int n,m,a[1100][1100],dfn[1100],low[1100],st[1100],ins[1100],num,v[1100],cnt,sp[1100],ok[1100],flag[1100],root;
 7 vector<int>son[1100],spn[1100];
 8 void tarjan(int x,int pre){
 9     dfn[x]=low[x]=++num;
10     if(x==root&&son[x].size()==0) spn[++cnt].push_back(x);
11     st[++st[0]]=x;
12     ins[x]=1;
13     for(int i=0;i<son[x].size();i++){
14         int y=son[x][i];
15         if(y==pre) continue;
16         if(!dfn[y]){
17             tarjan(y,x);
18             low[x]=min(low[x],low[y]);
19             if(low[y]>=dfn[x]){
20                 cnt++;
21                 int w;
22                 do{
23                     w=st[st[0]--];
24                     ins[w]=0;
25                     spn[cnt].push_back(w);
26                 }while(w!=y);
27                 spn[cnt].push_back(x);
28             }
29         }
30         else low[x]=min(low[x],dfn[y]);
31     }
32 }
33 int dfs(int x,int pre,int loc){//是二分图返回0,是奇圈返回1
34     v[x]=v[pre]^1;
35     //cout<<x<<" "<<v[x]<<endl;
36     for(int i=0;i<son[x].size();i++){
37         int y=son[x][i];
38         //cout<<y<<" "<<" "<<flag[y]<<" "<<v[y]<<endl;
39         if(!flag[y]||y==pre) continue;
40         if(v[y]==-1){
41             if(dfs(y,x,loc)) return 1;
42         }
43         else if(v[y]==v[x]) return 1;
44     }
45     return 0;
46 }
47 
48 int main(){
49     scanf("%d%d",&n,&m);
50     while(n!=0||m!=0){
51         int x,y;
52         for(int i=1;i<=m;i++){
53             scanf("%d%d",&x,&y);
54             a[x][y]=a[y][x]=1;
55         }
56         for(int i=1;i<=n;i++){
57             for(int j=1;j<=n;j++){
58                 if(a[i][j]||i==j) continue;
59                 son[i].push_back(j);
60             }
61         }
62         for(int i=1;i<=n;i++){
63             if(!dfn[i]) root=i,tarjan(i,0);
64         }
65         memset(v,-1,sizeof(v));
66         v[0]=0;
67         //cout<<cnt<<endl;
68         for(int i=1;i<=cnt;i++){
69             if(spn[i].size()==1) continue;
70             for(int j=0;j<spn[i].size();j++) flag[spn[i][j]]=1;
71             if(dfs(spn[i][0],0,i))
72                 for(int j=0;j<spn[i].size();j++)    
73                     ok[spn[i][j]]=1;
74             for(int j=0;j<spn[i].size();j++) flag[spn[i][j]]=0,v[spn[i][j]]=-1;
75         }
76         int ans=0;
77         for(int i=1;i<=n;i++) ans+=ok[i];
78         printf("%d\n",n-ans); 
79         for(int i=1;i<=n;i++){
80             dfn[i]=low[i]=0;
81             st[i]=0;
82             ins[i]=0;
83             ok[i]=0;
84             sp[i]=0;
85             son[i].clear();
86             spn[i].clear();
87         }
88         st[0]=0;
89         memset(v,-1,sizeof(v));
90         memset(a,0,sizeof(a));
91         num=cnt=0;
92         scanf("%d%d",&n,&m);
93     }
94     
95 }

 

相关文章: