算法导论 图论 22.2-6 好选手 坏选手

来源:互联网 发布:mysql删除表多个字段 编辑:程序博客网 时间:2024/04/30 03:55
 

22.2-6.好选手、坏选手。

很显然,这个问题等价于判断这个图是不是二分图,因为同类之间不能有关系,不同类之间可以有关系。将好选手归为一类,坏选手归为一类,不妨设为AB两类若好选手Ai和坏选手Bj之间有比赛,则有一条边相连。首先,若是某个图为二分图的话,当且仅当图中所有的回路都为偶数个顶点,顶点个数至少为2

证明很显然。

必要性,若是存在回路,则必然回路中的顶点必然是AB相间的,因为只有AB的顶点之间才会有边。则有Ai->Bj->....Am->Bn->Ai,所以回路中所有顶点个数必然是偶数个。

充分性,若是图中的回路的顶点数都为偶数个。不妨设为连通图。对于顶点V0,距离V0边为偶数的划为XY=V-X,则我们只需要证明,不存在顶点uv使得,且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;    

}

原创粉丝点击