// Author: sky
// Date: 2011.11.4
// Content: 图的相关程序
///
#include <iostream>
#include <string>
using namespace std;
#define DEFAULT_SIZE 20
#define DEFAULT_WEIGHT 0
bool visitable[DEFAULT_SIZE];// 标示节点是否被访问过
//
// 摔角选手goodguy 和badguy的分配问题
int color[DEFAULT_SIZE];//表示每个节点的颜色
enum{goodGuy=1,badGuy=2};
int colorFlag=goodGuy;
bool IsDesignFlag=true;
//
//打印两个点之间的线路(如果存在的话)
bool IsFind=false;
string Path="";// 记录所经过的线路
struct Graph //本程序采用邻接矩阵方式存储图
{
Graph();
bool Initialize(int vNum,int eNum,string nStr,int graType);
int GetVertexLoc(char a) const;//得到节点 在途中的标号 i
bool InsertNode(char beginNode,char endNode,int edgWeight);
bool IsAcylic();//判断一个图是否是有向无环图(采用拓扑排序的方法)
string node;//记录节点的字母表示
int weight[DEFAULT_SIZE][DEFAULT_SIZE];
int vertexNum,edgeNum,graphType;//分别代表 顶点个数 边的个数以及图的类型(1表示无向 2表示有向)
};
void DFS(Graph gra,int k=-1);//深度优先遍历(递归方法)
void BFS(Graph gra); //广度优先遍历
void IsDesign(Graph gra,int k=-1);// 实质是着色问题 即共两种颜色,图中相邻点不能为同一种颜色
//通过此函数判断能否着色成功
void PrintPath(Graph gra,char beginVertex,char endVertex);//k=-1表示 图中不存在该节点
Graph::Graph()
{
node="";
vertexNum=DEFAULT_SIZE;
edgeNum=DEFAULT_SIZE;
}
bool Graph::Initialize(int vNum,int eNum,string nStr,int graType)
{
if (nStr.length()!=vNum)
{
cout<<"The Number of Node must be"<<vNum;
return false;
}
vertexNum=vNum;
edgeNum=eNum;
graphType=graType;
node=nStr;
for (int i=0;i<vertexNum;i++)
{
for (int j=0;j<vertexNum;j++)
{
weight[i][j]=DEFAULT_WEIGHT;//权重初始化为0 同时也可以表示两个顶点不可达
}
visitable[i]=false;//初始化访问节点 为false
}
return true;
}
int Graph::GetVertexLoc(char a)const
{
for (int i=0;i<vertexNum;i++)
{
if (node[i]==a)
return i;
}
return -1;
}
bool Graph::InsertNode(char beginNode,char endNode,int edgWeight)
{
int i=GetVertexLoc(beginNode);
int j=GetVertexLoc(endNode);
if (i==-1||j==-1)
{
cout<<"Node is not in Graph"<<endl;
return false;
}
weight[i][j]=edgWeight;//表示有向图
if (graphType==1)
{
weight[j][i]=weight[i][j];//表示无向图
}
return true;
}
bool Graph::IsAcylic()//使用拓扑排序判断有向图是否存在环
{
if (graphType!=2)//判断是否是有向图
{
return false;
}
bool checked[DEFAULT_SIZE];
for (int i=0;i<vertexNum;i++)
{
checked[i]=false;
}
int inDegree=0;//inDegree 表示入度的个数
for(int i=0;i<vertexNum;i++)
{
checked[i]=false;
for (int j=0;j<vertexNum;j++)
{
if(weight[j][i]!=DEFAULT_WEIGHT&&(checked[i]==false)&&(checked[j]==false))
inDegree++;
}
if (inDegree==0)
{
checked[i]=true;
}
inDegree=0;
}
for(int i=vertexNum-1;i>=0;i--)
{
for (int j=0;j<vertexNum;j++)
{
if(weight[j][i]!=DEFAULT_WEIGHT&&(checked[i]==false)&&(checked[j]==false))
inDegree++;
}
if (inDegree==0)
{
checked[i]=true;
}
inDegree=0;
}
for(int i=0;i<vertexNum;i++)
{
if (checked[i]==false)
{
return false;//如果仍然存在没有被访问的点 说明存在环
}
}
return true;
}
void DFS(Graph gra,int k)
{
if(k==-1)//表示第一次执行 实质 是递归的最上层循环
{
for (int j=0;j<gra.vertexNum;j++)
{
if (!visitable[j])
{
DFS(gra,j);
}
}
}
else
{
cout<<gra.node[k]<<" ";//此处因为第一次执行的时候肯定visitable==false
visitable[k]=true;
for (int j=0;j<gra.vertexNum;j++)
{
bool judge=(gra.weight[k][j]!=DEFAULT_WEIGHT)&&(visitable[j]==false);
if (judge)
{
DFS(gra,j);
}
}
}
}
void BFS(Graph gra)
{
for (int i=0;i<gra.vertexNum;i++)
{
if (!visitable[i])
{
cout<<gra.node[i]<<" ";
visitable[i]=true;
for (int j=0;j<gra.vertexNum;j++)
{
if ((gra.weight[i][j]!=DEFAULT_WEIGHT)&&(!visitable[j]))
{
cout<<gra.node[j]<<" ";
visitable[j]=true;
}
}
}
}
}
void IsDesign(Graph gra,int k)//着色问题的核心函数
{
if(k==-1)//表示第一次执行
{
bool aloneVertexFlag=false;
for (int j=0;j<gra.vertexNum;j++)
{
if (visitable[j]==false)
{
IsDesign(gra,j);
}
}
}
else
{
visitable[k]=true;
color[k]=colorFlag;
for (int j=0;j<gra.vertexNum;j++)
{
if (gra.weight[k][j]!=DEFAULT_WEIGHT)
{
if (visitable[j]==false)
{
if (color[k]==goodGuy)//每遍历到一个节点之后 就改变一次colorFlag
{
colorFlag=badGuy;
}
else
{
colorFlag=goodGuy;
}
IsDesign(gra,j);
}
else //否则的话 就表示 两个点有连线 而且已经被访问过了,所以可以用来检测是否能涂色
{
if(color[k]==color[j])
{
IsDesignFlag=false;
}
}
}
}
}
}
void PrintPath(Graph gra,char beginVertex,char endVertex)//查找路线的核心函数
{
int k=gra.GetVertexLoc(beginVertex);//找到起始顶点 在邻接矩阵中的位置
if (k==-1||(gra.GetVertexLoc(endVertex)==-1))
{
cout<<"illegal Vertex"<<endl;
return;
}
visitable[k]=true;
Path+=gra.node[k];
Path+="-->";
if(endVertex==gra.node[k])
{
IsFind=true;
return;
}
for (int j=0;j<gra.vertexNum;j++)
{
if((gra.weight[k][j]!=DEFAULT_WEIGHT) &&(visitable[j]==false))
{
PrintPath(gra,gra.node[j],endVertex);
if (IsFind==true)return;
}
}
if (IsFind==false)//如果没找到 就取消线路上的节点
{
Path=Path.substr(0,Path.size()-4);
}
}
void FirstProblem()//
{
int verNum=0,edgNum=0,graType=1;
string nodeStr;
Graph gra;
cout<<"\n\n\n\nInput Vertex Number: ";cin>>verNum;
cout<<"Input Edge Number: "; cin>>edgNum;
cout<<"Input Node String with no space(eg, ABCDEF): ";cin>>nodeStr;
if(!gra.Initialize(verNum,edgNum,nodeStr,graType))
{
cout<<"Initialization error!";
return ;
}
for (int i=0;i<edgNum;i++)
{
char a,b;
int eweight=1;//此处设定了默认的权重为1 因为不涉及权重 固不输入权重
cout<<"\nPlease Input edge "<<(i+1)<<" :";
cin>>a>>b;
if(!gra.InsertNode(a,b,eweight)) return;
}
IsDesign(gra);
cout<<"\nIs possible to Design? The answer is :\n";
if(IsDesignFlag)
{
cout<<"\t\t\tYes, you can get the answer like that"<<endl;
for (int i=0;i<verNum;i++)
{
cout<<'\n\t'<<gra.node[i]<<" locates ";
if (color[i]==1)
{
cout<<" goodGuy"<<endl;
}
else
{
cout<<" badGuy"<<endl;
}
}
}
else
{
cout<<"\n!No solution"<<endl;
}
}
void SencondProblem()//
{
int verNum=0,edgNum=0,graType=2;//2表示有向图
string nodeStr;
Graph gra;
cout<<"\n\n\n\nInput Vertex Number: ";cin>>verNum;
cout<<"Input Edge Number: "; cin>>edgNum;
cout<<"Input Node String with no space(eg, ABCDEF): ";cin>>nodeStr;
if(!gra.Initialize(verNum,edgNum,nodeStr,graType))
{
cout<<"Initialization error!";
return ;
}
for (int i=0;i<edgNum;i++)
{
char a,b;
int eweight=1;//此处设定了默认的权重为1 因为不涉及权重 固不输入权重
cout<<"\nPlease Input edge "<<(i+1)<<" :";
cin>>a>>b;
if(!gra.InsertNode(a,b,eweight)) return ;
}
if(gra.IsAcylic()==false)//判断是否为有向无环图
{
cout<<" Sorry, This is not a directed acylic Graph ";
return ;
}
char beginVertex,endVertex;
cout<<"\n\nInput two Vertex: ";
cin>>beginVertex>>endVertex;
PrintPath(gra,beginVertex,endVertex);
if (IsFind)
{
Path=Path.substr(0,Path.size()-3);
cout<<"The Path is : "<<Path;
}
else
{
cout<<"\n!Sorry, Two Vertex can't communication";
}
}
int main(int agrc,char* argv[])
{
Graph gra=InputGraph();
cout<<"Print by DFS:"<<endl;
DFS(gra);
cout<<"\nPrint by BFS:"<<endl;
for(int i=0;i<gra.vertexNum;i++)
visitable[i]=false;
BFS(gra);
cout<<"The first Problem :\n";
FirstProblem();
cout<<"The second Problem :\n";
SencondProblem();
return 0;
}