ACM-天梯赛赛前复习

本文深入解析拓扑排序、深度优先搜索(DFS)及广度优先搜索(BFS)的概念与应用,通过具体实例讲解如何利用这些算法解决有向无环图(DAG)中的排序问题。文章提供了C++实现代码,详细阐述了正向建图与反向建图的方法,并以HDU4857题目为例,展示了如何结合优先队列进行反向建表,确保数字小的元素在排序中靠前。

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

拓补排序、dfs、bfs

理解几个名词:

DAG :有向无环图
入度:指向这个元素的行为。
出度:从这个元素指出去的行为。
正向建图与反向建图:根据入度或出度的某一方向往最后的答案数组中放元素。
hdu4857
思路:利用每个元素的入度(出度)来首先拿出一个元素,然后根据这个元素相关的向量来(1)先把相关的入度(出度)都减一,(2)遍历一遍看有没有元素的入度(出度)为零的。(3)为零了再push进入队列中,这道题结合优先队列反向建表的原因就是题干中有数字小的在前。
(易错:每次对于向量数组的清空(clear()),因为这个原因wa了一次。)

#include <iostream>
#include<cstdio>
#include <cstring>
#include <queue>
#include<vector>
#define maxn 30050
using namespace std;

vector<int>b[maxn]; //对每个与自己相关的元素放入一个空间内,对那个空间的进行遍历
     //向量数组,用于储存每个和自己相关的元素
priority_queue<int>q;
int out_num[maxn];    //本题用出度来运算
int ptotal,nodetotal;
int ans[maxn];  //最终答案数组


int main(int argc, char const *argv[])
{
	int T;
	cin>>T;
	while(T--){
		for (int i = 1; i <= ptotal; ++i)
		{
			b[i].clear();
		}
		memset(out_num,0,sizeof(out_num));
		memset(ans,0,sizeof(ans));
		// cin>>ptotal>>nodetotal;
		scanf("%d%d",&ptotal,&nodetotal);
		int s,t;
		for (int i = 1; i <= nodetotal; ++i)
		{
			// cin>>s>>t;
			scanf("%d%d",&s,&t);
			out_num[s]++;
			b[t].push_back(s);
		}
		int u=0;
		for (int i = 1; i <= ptotal; ++i)
		{
			if (out_num[i]==0)
			{
				// ans[u++]=i;
				q.push(i);
				// break;
			}
		}
		while(!q.empty()){
			int tem = q.top();
			q.pop();
			ans[u++]=tem;
			for (int i = 0; i < b[tem].size(); ++i)
			{
				if (--out_num[b[tem][i]]==0)
				{
					q.push(b[tem][i]);
				}
			}
			
		}
		for (int i = ptotal-1; i >=0; --i)
		{
			if (i==0)
			{
				// cout<<ans[i]<<endl;
				printf("%d\n",ans[i]);
			}
			// else cout<<ans[i]<<" ";
			else printf("%d ",ans[i]);
		}
	}
	return 0;
}

以下dfs和bfs模板纯属个人的小小总结,如有觉得改正或有错误的地方,欢迎评论区指出

dfs :

运用递归的思想,通过控制层数来控制递归的层数。每层通过一个for循环来遍历是否有负荷的情况,有了就进入下一层;遍历到头也没有符合的就退到上一层。
模板:

#include<iostream>
using namespace std;
// int a[12][12];
// int mark[12][12]
bool check(int x;int y){

}

void dfs(/*控制迭代的东西*/int m,int n){ //或者是迭代的代数。
	for (int i =1; i <=n ; ++i)
	{
		if (check())
		{
			//输出或记录

			//判断是否跳出这一层的dfs
			if/*控制迭代的东西条件满足了*/{
				//就break;
			}

			//check成立之后应该改变标记条件

			//进入下一层dfs()这次的应该就是下一层的坐标。/其他情况就是下一层的迭代的层数。

			//如果从dfs中(上一层的dfs)跳出=>就要把原来的标记条件改回去。


		}
	}
}
int main(int argc, char const *argv[])
{
	//放入第一次的数据进去
	dfs(/* 第一次的*/);
	return 0;
}

bfs:

并没有用到递归的思想,而是像扩散一样将附近的所有情况都走完了,再继续往外扩散。储存数据的东西是队列,如果想记录路径就需要在结构体中写一个参数来记录走的步数(扩散的长度),最后可以通过一个栈来通过结构体中的那个记录走的步数的参数来回溯找到路径。

bfs  //一般都结合队列=>而push进队列的都是结构体
//一般会来一个结构体
struct node
{
	int x,y;
};

void bfs(int can1,int can2,){  //bfs的原理就是首先push进去一个元素,
	                           //再通过循环来push很多元素,再筛选,记录储存等等,
	                           //每次都会将临时拿出的判断的元素再pop掉,避免重复。
	//也要先创建一个对象
	node eg;
	eg.--=--;
	eg.--=--;
	q.push(eg);//往队列中拿进一个元素
	while(!q.empty()){
		//但是在bfs中判断的只能是结构体=>临时创一个对象=>以此来获取所有性质。
		node tem=q.front();//先取出某元素
		q.pop();   //再将这个元素拿走。
		//虽然不需要判断这个已经有的点的情况,但是还是要记录下来,因为有可能
		//要在后边延申点的时候用到。(加方向向量的时候会需要)
		for (int i = 0; i < ; ++i)
		{
			//在这里加方向向量来做延申。
			if ()//满足可以延伸的条件
			{
				//加入到队列中
				q.push();
			}
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值