【图】BFS遍历、DFS遍历、Topology排序、判断二分性

本文探讨了如何进行图的Breadth First Search (BFS) 和 Depth First Search (DFS) 遍历,详细解释了拓扑排序的实现,并讲解了如何判断图的二分性。通过实例和代码解析,帮助读者深入理解这些图论概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

苦逼练代码!





# include<stdio.h>

# include<queue>
# include<stack>
using namespace std;

# define N 103
# define M 1003

int g[N][N];
int bpG[N][N];
int visit[N];

void initG()
{
	memset(g,0,sizeof(g));
	g[1][2]=1;
	g[1][3]=1;
	g[2][1]=1;
	g[2][4]=1;
	g[2][5]=1;
	g[3][1]=1;
	g[3][6]=1;
	g[3][7]=1;
	g[4][2]=1;
	g[4][6]=1;
	g[4][8]=1;
	g[5][2]=1;
	g[5][6]=1;
	g[5][7]=1;
	g[6][3]=1;
	g[6][4]=1;
	g[6][5]=1;
	g[7][3]=1;
	g[7][5]=1;
	g[8][4]=1;

	g[9][10]=1;
	g[9][11]=1;
	g[10][9]=1;
	g[11][9]=1;
	g[11][12]=1;
	g[12][11]=1;
}

void initBiPartionG()
{
	memset(bpG,0,sizeof(bpG));
	bpG[1][2]=1;
	bpG[1][4]=1;
	bpG[2][1]=1;
	bpG[2][3]=1;
	bpG[2][5]=1;
	bpG[3][1]=1;
	bpG[3][2]=1;
	bpG[4][1]=1;
	bpG[4][7]=1;
	bpG[5][2]=1;
	bpG[5][6]=1;
	bpG[5][8]=1;
	bpG[6][5]=1;
	bpG[7][4]=1;
	bpG[7][8]=1;
	bpG[8][5]=1;
	bpG[8][7]=1;
}

void BFS(int startNode)
{
	int curNode,i,n=13;//只考虑前12个节点

	queue<int> q;
	q.push(startNode);
	visit[startNode]=1;//加入队列时就设置visit
	while(!q.empty())
	{
		curNode=q.front();
		q.pop();
		printf("%d ", curNode);
		for(i=1;i<n;i++)
		{
			if(g[curNode][i]==1 && visit[i]==0)
			{
				q.push(i);
				visit[i]=1;//加入队列时就设置visit
			}
		}
	}
}

void DFS(int startNode)
{
	int curNode,i,n=13;//只考虑前12个节点

	stack<int> s;
	s.push(startNode);
	//visit[startNode]=1;
	while(!s.empty())
	{
		curNode=s.top();
		s.pop();
		if(visit[curNode]==1)
		{
			continue;
		}
		visit[curNode]=1;//退出队列时【才需要】设置visit
		printf("%d ", curNode);
		for(i=1;i<n;i++)
		{
			if(g[curNode][i]==1 && visit[i]==0)
			{
				s.push(i);
				//visit[i]=1;
			}
		}
	}
}

void Topology()//假设小id指向大id,将无向图转换为有向图无环图(DAG)
{
	int i,j,k,n=9;//只考虑前8个节点
	int inCome[9];
	memset(inCome,0,sizeof(inCome));
	for(i=1;i<n;i++)
	{
		for(j=i+1;j<n;j++)
		{
			if(g[i][j]==1)
			{
				inCome[j]++;
			}
		}
	}
	int visit[9];
	memset(visit,0,sizeof(visit));
	for(i=1;i<n;i++)//依次找到第i个节点,方法如下:
	{
		//for(j=1;j<n;j++)//依次扫描inCome的每个元素
		for(j=n-1;j>=1;j--)//为了不让结果是1-8,我们从大id的节点开始扫描
		{
			if(inCome[j]==0 && visit[j]==0)
			{
				printf("%d ", j);
				visit[j]=1;
				for(k=1;k<n;k++)
				{
					if(g[j][k]==1)
					{
						inCome[k]--;
					}
				}
				break;
			}
		}
	}

	//正常的思路是使用队列,保存目前income=0的点,然后出一次队,邻接点的income减1,如果减1后income变为0,则入队;while(!queue.empty())。	
	printf("\n");
	memset(inCome,0,sizeof(inCome));
	for(i=1;i<n;i++)
	{
		for(j=i+1;j<n;j++)
		{
			if(g[i][j]==1)
			{
				inCome[j]++;
			}
		}
	}
	queue<int> q;
	q.push(1);
	while(!q.empty())
	{
		k=q.front();
		q.pop();
		printf("%d ", k);
		for(i=k+1;i<n;i++)
		{
			if(g[k][i]==1)
			{
				inCome[i]--;
				if(inCome[i]==0)
				{
					q.push(i);
				}
			}
		}
	}
}

void IsBiPartion(int g[][N])//本质和BFS一样,只不过要识别哪些点位于哪一层
{
	int i,j,curLevel=-1,curNode,n=9;//只考虑前8个节点
	int visitLevel[9];
	memset(visitLevel,0,sizeof(visitLevel));

	queue<int> q;
	q.push(curLevel);//增加标识层节点
	q.push(1);
	visitLevel[1]=curLevel;
	while(!q.empty())
	{
		curNode=q.front();
		q.pop();
		if(curNode<0)//当前是 标识层节点
		{
			curLevel--;//层数减1,由“-1”层变成“-2”层
			q.push(curLevel);//在队列中增加标识下一层的节点
			curNode=q.front();
			q.pop();
			if(curNode<0)//如果在一个标识层节点 后面紧跟着 另一个标识层节点,说明遍历结束
			{
				break;
			}
		}
		printf("第【%d】层==>%d\n", -visitLevel[curNode], curNode);//输出每一而node的访问层
		for(i=1;i<n;i++)
		{
			if(g[curNode][i]==1 && visitLevel[i]==0)
			{
				q.push(i);
				visitLevel[i]=curLevel;
			}
		}
	}

	//遍历所有的边,看这些边的两个端点的层数有没有都是【同奇同偶】的情况,如果有,说明set内部出现了边,表示不可二分,否则可二分
	for(i=1;i<n;i++)
	{
		for(j=i+1;j<n;j++)
		{
			if(g[i][j]==1 && (visitLevel[i]%2)==(visitLevel[j]%2))
			{
				printf("not a BiPartion graph!\n");
				return;
			}
		}
	}
	printf("is a BiPartion graph!\n");
}

int main()
{
	int i,n=13;

	initG();

	printf("BFS:\n");
	memset(visit,0,sizeof(visit));
	for(i=1;i<n;i++)
	{
		if(visit[i]==0)
		{
			BFS(i);
		}
	}
	printf("\n");

	printf("BFS:\n");
	memset(visit,0,sizeof(visit));
	for(i=1;i<n;i++)
	{
		if(visit[i]==0)
		{
			DFS(i);
		}
	}
	printf("\n");

	printf("Topology:\n");
	memset(visit,0,sizeof(visit));
	Topology();
	printf("\n");

	
	printf("IsBiPartion:\n");
	IsBiPartion(g);
	printf("\n");

	printf("IsBiPartion:\n");
	initBiPartionG();
	IsBiPartion(bpG);
	printf("\n");
	

	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值