图怎么遍历

文章介绍了在给定有向图中,针对每个节点找到能到达的编号最大的节点的问题。首先提出了一种使用深度优先搜索(DFS)的方法,然后指出对于大规模数据,通过反向建边并从N开始逐个节点处理更高效。最后提供了两种方法的代码实现。
摘要由CSDN通过智能技术生成

给出 N 个点,M 条边的有向图,对于每个点 v,求 A(v) 表示从点 v 出发,能到达的编号最大的点。

Input

第 11 行 22 个整数 ,N,M,表示点数和边数。

接下来 M 行,每行 22 个整数 ,Ui​,Vi​,表示边 (,)(Ui​,Vi​)。点用 1,2,…,1,2,…,N 编号。

Output

一行 N 个整数 (1),(2),…,()A(1),A(2),…,A(N)。

Sample 1

InputcopyOutputcopy
4 3
1 2
2 4
4 3
4 4 3 4

Hint

  • 对于 100%100% 的数据,1≤N,M≤1e3。
  • #include<iostream>
    #include<algorithm>
    #include<vector>
    #include<queue>
    #include<map>
    using namespace std;
    vector<int> a[1005];//用于储存每一个父节点包含的数据
    int ans = 0;
    bool visited[1005];//用来对已经走过的点进行标记,防止图中有环的时候陷入循环
    
    void bfs(int k) {
    	queue<int> q;//先定义一个队列
    	q.push(k);//第一项先入队
    	int t = 0;
    
    	while (q.size()) {//当它不为空的时候说明元素并没有全部遍历
    		t = q.front();
    		q.pop();//已经获取了,让他进行出栈
    		ans = max(ans, t);//每一次遇到都进行比较,找到最大的
    		for (auto& y : a[t]) {//a相当于二维数组,a[]可以看成是一个地址,所以有&,用这种方式获取a[t]中的所有
    			if (visited[y]==0) {//如果它没有经过入栈则进入
    				q.push(y);
    				visited[y] = true;//进去了就标记
    			}
    		}
    	}
    }
    
    int main() {
    	int n, m, x, y;
    	cin >> n >> m;
    
    	for (int i = 1; i <= m; i++) {
    		cin >> x >> y;
    		a[x].push_back(y);//用来将一个数对应的连接的分支储存,如a[1]里面放2 3,那么说明图中的1连接着2和3两个
    	}
    
    	for (int i = 1; i <= n; i++) {//对每一个节点遍历
    		fill(visited, visited + 1005, false);//用fill让visited中的全部内容变为false,用于从下一次的循环
    		//fill(a.begin(),a.end(),x);
    		bfs(i);
    		cout << ans << ' ';
    		ans = 0;
    	}
    
    	return 0;
    }

    对于1e5的数据范围来说的话,上面这种方法明显超时了,需要用一种更加快的方法。

  • 按题目来每次考虑每个点可以到达点编号最大的点,不如考虑较大的点可以反向到达哪些点

  • 循环从N到1,则每个点i能访问到的结点的A值都是i

    每个点访问一次,这个A值就是最优的,因为之后如果再访问到这个结点那么答案肯定没当前大了

  • #include <iostream>
    #include <cstdio>
    #include <vector>
    using namespace std;
    
    #define MAXL 100010
    
    int N, M, A[MAXL];
    vector<int> G[MAXL]; //vector存图 
    
    void dfs(int x, int d) {
    	if(A[x]) return; //访问过
    	A[x] = d;//赋予能得到的最大的
    	for(int i=0; i<G[x].size(); i++)
    		dfs(G[x][i], d);
    }
    
    int main() {
    	int u, v;
    	scanf("%d%d", &N, &M);
    	for(int i=1; i<=M; i++) {
    		scanf("%d%d", &u, &v);
    		G[v].push_back(u); //反向建边 
    	}
    	for(int i=N; i; i--) dfs(i, i); 
    	for(int i=1; i<=N; i++) printf("%d ", A[i]);
    	printf("\n");
    	return 0;
    }

  • 运用dfs和bfs遍历图
    输入为n与第从2到n的父节点
    如5 1 1 2 3意思为2连接在1上面,3连接在1上面,4连接在2上面,5,3

  • #include<iostream>
    #include<algorithm>
    #include<vector>
    #include<stack>
    #include<queue>
    using namespace std;
    int N, b[100];
    vector<int>a[100];//每一个a[i]相当于图的第几个节点,动态开辟空间,和二维数组有相似之处
    void dfs(int k)
    {
    	cout << k << ' ';//每次开始前先进行输出的操作
    	for (auto& y : a[k])//根据前一个遍历的数找到它对应的节点,直到没有分支再往上一步遍历
    		dfs(y);//进行递归操作
    }
    
    void bfs(int k)
    {
    	queue<int>q;//队列
    	q.push(k);//首元素入栈
    	while (q.size())//当队列中没有元素的时候退出
    	{
    		int x = q.front(); q.pop();//先拿到先进去的元素,再把它删除,留下来的就是下次应该往队列里堆的节点名
    		cout << x << ' ';
    		for (auto& y : a[x])//遍历将整个的所有分支全都入队列
    			q.push(y);
    	}
    }
    
    int main()
    {
    	cin >> N;
    	for (int i = 2; i <= N; i++)//因为首节点已经确定是1,那么名称从2开始
    	{
    		cin >> b[i];
    		a[b[i]].push_back(i);//把第i个放在所对应的父节点里
    	}
    	for (int i = 2; i <= N; i++)
    		sort(a[i].begin(), a[i].end());//遍历每一个父节点,把它们排成有序的
    	dfs(1);
    	cout << '\n';
    	bfs(1);
    	return 0;
    }

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值