Luogu P3916 图的遍历

P3916 图的遍历

题目描述

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

输入输出格式

输入格式:

 

第1 行,2 个整数 $N,M$ 。

接下来 $M$ 行,每行2个整数 $U_i,V_i$​ ,表示边 $(U_i,V_i)$ 。点用 $1, 2,\cdots,N$ 编号。

 

输出格式:

 

$N$ 个整数 $A(1),A(2),\cdots,A(N)$ 。

 

输入输出样例

输入样例#1:
4 3
1 2
2 4
4 3
输出样例#1:
4 4 3 4
说明

• 对于60% 的数据, $1 \le N . K \le 10^3$ ;

• 对于100% 的数据, $1 \le N , M \le 10^5$ 。

 

有部分分,那就先打个暴力。

#include <iostream>
#include <cstring>
#include <cstdio>
#define Edge_max 100008

using namespace std;

int n, m, outdgr[Edge_max], ans;

bool vis[Edge_max];

int u[Edge_max], v[Edge_max], first[Edge_max], next[Edge_max];

void dfs(int k) {
	ans = max(ans, k);
	if(outdgr[k] == 0) {
		
		return ;
	}
	int s = first[k];
	while(s != -1) {
		if(!vis[v[s]]) {
			vis[v[s]] = 1;
			dfs(v[s]);
			vis[v[s]] = 0;
		}
		s = next[s];
	}	
}

int main() {
	scanf("%d%d", &n, &m);
	memset(first, -1, sizeof(first));
	for(int i=1; i<=m; i++) {
		scanf("%d%d", &u[i], &v[i]);
		next[i] = first[u[i]];
		first[u[i]] = i;
		outdgr[u[i]]++;
	}
	for(int i=1; i<=n; i++) {
		memset(vis, 0, sizeof(vis));
		ans = 0;
		dfs(i);
		printf("%d ", ans);
	}
}

  

  

 

铛啷啷,就是这样的。

然后我们考虑反向建边,这样就不会有后效性。

然后把沿途经过的点都标记一遍,就$AC$了

#include <iostream>
#include <cstring>
#include <cstdio>
#define Edge_max 100008

using namespace std;

int n, m, ans, A[Edge_max];

bool vis[Edge_max];

int u[Edge_max], v[Edge_max], first[Edge_max], next[Edge_max];

void dfs(int k) {
	A[k] = max(A[k], k);
	int s = first[k];
	while(s != -1) {
		if(!A[v[s]]) A[v[s]] = A[k], dfs(v[s]);
		s = next[s];
	}
}

int main() {
	scanf("%d%d", &n, &m);
	memset(first, -1, sizeof(first));
	for(int i=1; i<=m; i++) {
		scanf("%d%d", &u[i], &v[i]);
		swap(u[i], v[i]);
		next[i] = first[u[i]];
		first[u[i]] = i;
	}
	for(int i=n; i>=1; i--) {
		ans = 0;
		dfs(i);
	}
	for(int i=1; i<=n; i++) printf("%d ", A[i]);
	return 0;
}

  

posted @ 2018-05-17 21:52  Mystical-W  阅读(203)  评论(0编辑  收藏  举报