建补图,是两个不仇恨的骑士连边,如果有环,则可以凑成一桌和谐的打麻将
不能直接缩点,因为直接缩点求的是连通分量,点双缩点只是把环缩起来
普通缩点 点双缩点
由图可知,左图中的缩法不符题意,而右图两个缩完后的点都满足题意
然后题中说必须要奇数个骑士参加会议,即找奇圈(有奇数个点的圈)
问题就转化成缩点后判断一个点是否在奇圈里,这就用到了点双的性质
点双连通分量有两个性质: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 }