22.2-6.好选手、坏选手。
很显然,这个问题等价于判断这个图是不是二分图,因为同类之间不能有关系,不同类之间可以有关系。将好选手归为一类,坏选手归为一类,不妨设为A、B两类若好选手Ai和坏选手Bj之间有比赛,则有一条边相连。首先,若是某个图为二分图的话,当且仅当图中所有的回路都为偶数个顶点,顶点个数至少为2。
证明很显然。
必要性,若是存在回路,则必然回路中的顶点必然是AB相间的,因为只有AB的顶点之间才会有边。则有Ai->Bj->....Am->Bn->Ai,所以回路中所有顶点个数必然是偶数个。
充分性,若是图中的回路的顶点数都为偶数个。不妨设为连通图。对于顶点V0,距离V0边为偶数的划为X,Y=V-X,则我们只需要证明,不存在顶点u,v使得,且Euv E,假设存在边uv,则uv距离v0的边都为偶数,则回路v0~u->v~v0的边长为奇数,矛盾,所以边uv。
所以我们只需要证明是否存在长度为奇数的回路就可以判断是不是二分图。
所以当我们进行BFS时扫描到相邻灰色节点时,只需要判断一下这两个节点距离扫描根节点的距离,若是距离之和为偶数,则必然有长为奇数的回路。
我们再增加一个变量表示是好选手或是坏选手
参考算法导论伪代码修改的伪代码:
BFS(G,s)
1.for each vertex u∈V[G]-s
2. do color[u]<---white
3. d[u]<---∞
4. π[u]<---NIL
5. type[u]<---false
6.Color[s]<---gray
7.type[s]<---true
8.D[s]<---0
9.π[s]<---NIL
10.Q<---φ
11.ENQUEUE(Q,s)
12.While(Q<>φ)
13. Do u<---DEQUEUE(Q)
14. For each v∈Adj[u]
15. Do if(color[v]=WHITE&&(d[v]+d[u])%2=0)存在奇数长度简单回路break;
16. if color[v]=WHITE
17. Then color[v]<---GRAY
18. Type[v]<---!type[u]
19. D[v]<---d[u]+1
20. Π[v]<---u
21. ENQUEUE(Q,v)
22. Color[u]=black
#include<queue>
#include<cstdlib>
#include<fstream>
#define V 10
#define MAX (~(1<<(8*sizeof(int)-1)))
enum Color{WHITE,GRAY,BLACK};
#define Type bool
using namespace std;
int m[V][V];
Color color[V];
int d[V];
int p[V];
Type type[V];
int num;
queue<int> q;
void printPath(int s){
int v=s;
printf("存在奇数回路%d ",s);
while(p[s]!=v){
printf("%d ",p[s]);
s=p[s];
}
printf("%d\n",v);
}
void clear(){
for(int i=0;i<V;i++)
{
for(int j=0;j<V;j++)m[i][j]=0;
color[i]=WHITE;
type[i]=false;
}
}
int BFS(int s){
for(int i=0;i<num;i++)
{
color[i]=WHITE;
d[i]=MAX;
p[i]=-1;
//type[i]=false;
}
color[s]=GRAY;
d[s]=0;
p[s]=-1;
type[s]=true;
q.push(s);
while(!q.empty()){
int u=q.front();q.pop();
for(int v=0;v<num;v++)
{
if(m[u][v]!=0&&color[v]==GRAY&&(d[u]+d[v])%2==0){//将在回路长度为奇
//if((d[u]+d[v])%2==0){printf("存在回路长度为奇,%d %d\n",u,v);
char *path[v];
printf("u=%d v=%d du=%d dv=%d m=%d",u,v,d[u],d[v],m[u][v]);
memset(path,0,sizeof(path));
int vp=p[v];
p[v]=u;
while(p[u]!=vp){//由BFS性质知道两者的路径长度必然相等
int temp=v;
v=vp;
vp=p[vp];
p[v]=temp;
u=p[u];
}
p[vp]=v;
printPath(p[u]);
return 0;
}
if(m[u][v]!=0&&color[v]==WHITE)
{
color[v]=GRAY;
d[v]=d[u]+1;
p[v]=u;
q.push(v);
type[v]=!type[u];
}
}
color[u]=BLACK;
}
return 1;
}
int main()
{
fstream f;
int t;
int u,v;
f.open("input22.2-6.txt");
f>>t;
for(int i=0;i<t;i++){
//
clear();
printf("样例%d\n",i);
f>>num;
for(int i=0;i<num;i++){
f>>u>>v;
m[u][v]=m[v][u]=1;
//printf("%d %d\n",u,v);
}
/*for(int i=0;i<4;i++)
{
for(int j=0;j<8;j++)
printf("m[%d][%d]=%d\t",i,j,m[i][j]);
printf("\n");
}
*/
if(BFS(0)){
printf("成功指定\n");
for(int i=0;i<num;i++)
if(type[i])printf("%d 好选手\n",i);
else printf("%d 坏选手\n",i);
}
}
f.close();
system("pause");
return 0;
}