洛谷 P3916 图的遍历

图的遍历

题目描述

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

输入格式

1 1 1 2 2 2 个整数 N , M N,M N,M,表示点数和边数。

接下来 M M M 行,每行 2 2 2 个整数 U i , V i U_i,V_i Ui,Vi,表示边 ( U i , V i ) (U_i,V_i) (Ui,Vi)。点用 1 , 2 , … , N 1,2,\dots,N 1,2,,N 编号。

输出格式

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

样例 #1

样例输入 #1

4 3
1 2
2 4
4 3

样例输出 #1

4 4 3 4

提示

  • 对于 60 % 60\% 60% 的数据, 1 ≤ N , M ≤ 1 0 3 1 \leq N,M \leq 10^3 1N,M103
  • 对于 100 % 100\% 100% 的数据, 1 ≤ N , M ≤ 1 0 5 1 \leq N,M \leq 10^5 1N,M105

满分题解:https://www.luogu.com.cn/article/cuelm1wr
主要思路:与其思考如何到达最大的点,不如思考较大的点能够到达的点。然后使用vis数组防止重复访问,提高运行效率

#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;
}

个人思路1:与满分题解类似,只不过没有思考到从最大的点开始遍历dfs,导致有一个测试样例超时(使用vis形同虚设,因为同一个点需要反复更新)

个人思路2: 20分。妄图使用拓扑结构来遍历整个图,却不知序号最大的点未必是出度为0的点。

#include <bits/stdc++.h>
using namespace std;
vector<int> from[100055];
bool vis[100005] = {0};
int ans[100055] = {0},ru[100005] = {0};
int n,m;
void dfs()
{
	
//	cout<<now<<' '<<anss<<endl;

	stack<int> s;
	for(int i = 1;i<=n;i++)
	if(ru[i] == 0)
	s.push(i);
	
	while(!s.empty())
	{
		int a = s.top();//cout<<a<<endl;
		s.pop();
		vector<int>::iterator it = from[a].begin();
		for(;it!=from[a].end();it++)
		{
			if(ans[*it]<ans[a])
			{
				ans[*it] = ans[a];
				
//				cout<<*it<<' '<<ans[*it]<<endl;
//				s.push(*it);
//				vis[*it] = true;
			}
			ru[*it]--;
			if(ru[*it] == 0) s.push(*it);
		}
//	}
}}
int main()
{
	cin>>n>>m;
	for(int i = 0;i<=n;i++)
{
	from[i].clear();
	}
	for(int i=0;i<m;i++)
	{
		int a,b;
		cin>>a>>b;
		from[b].push_back(a);
		ru[a]++;
	}
	cout<<ru[37]<<endl;
	for(int i=1;i<=n;i++) ans[i] = i;
//	for(int i=1;i<=n;i++)
//	{
//		if(vis[i] == false) dfs(i);
		cout<<ans[i]<<' ';
//	}
dfs();
	for(int i=1;i<=n;i++) cout<<ans[i]<<' ';
}
  • 14
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值