题目描述
给出 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 1≤N,M≤103。
- 对于 100 % 100\% 100% 的数据, 1 ≤ N , M ≤ 1 0 5 1 \leq N,M \leq 10^5 1≤N,M≤105。
解题思路:
在读完题之后,顺着题的描述很容易想到可以对每个点进行一次bfs来寻找最大值
显然,这道题不会这么简单
如果这个时候仍不能换个角度考虑的话,那么我们会想到
如果能够到达一个已经bfs过的点,那么就能到达它所能到达的所有点,直接将这些点标记并返回最大值即可
然后优化之后发现还是会TLE
那怎么办呢
这时我们可以运用逆向思维,与其考虑能够到达的最大值点,不如直接考虑最大值点能到达哪些点
那么思路一下就清晰起来了
首先是存图的操作,用vector存图,同时要注意将有向边反向
int main()
{
int n, m, tail, head;
cin >> n >> m;
for (int i = 0; i < m; i++)
{
cin >> tail >> head;
map[head].push_back(tail);//反向存储有向边
}
return 0;
}
然后就是从最大值点开始依次进行bfs
int main()
{
int n, m, tail, head;
cin >> n >> m;
for (int i = 0; i < m; i++)
{
cin >> tail >> head;
map[head].push_back(tail);
}
return 0;
for (int i = n; i >= 1; i--)
{
if (!(book[i]))//注意已经到访问的节点无需再次访问
{
bfs(i);
}
}
}
以下是bfs()的实现
const int max_n = int(1e5) + 1;
vector<int> map[max_n];//存图,下标表示节点
queue<int> bfs_queue;//bfs队列
bool book[max_n] = { false };//节点标记物,下标表示节点
int max_id[max_n] = { 0 };//数据处理结果,下标表示节点
void bfs(int now)//now为最大值
{
bfs_queue.push(now);
book[now] = true;//标记起点
max_id[now] = now;
while (!(bfs_queue.empty()))
{
for (int i = 0; i < int(map[bfs_queue.front()].size()); i++)//访问从当前队首元素所能访问的所有节点
{
if(!(book[map[bfs_queue.front()][i]]))
{
bfs_queue.push(map[bfs_queue.front()][i]);
book[map[bfs_queue.front()][i]] = true;//注意已经访问过的点要标记,且无需取消标记
max_id[map[bfs_queue.front()][i]] = now;//所有能访问的节点最大值均为now
}
}
bfs_queue.pop();//队首节点尝试完毕,出队
}
}
完整的代码实现如下
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
const int max_n = int(1e5) + 1;
vector<int> map[max_n];
queue<int> bfs_queue;
bool book[max_n] = { false };
int max_id[max_n] = { 0 };
void bfs(int now)
{
bfs_queue.push(now);
book[now] = true;
max_id[now] = now;
while (!(bfs_queue.empty()))
{
for (int i = 0; i < int(map[bfs_queue.front()].size()); i++)
{
if(!(book[map[bfs_queue.front()][i]]))
{
bfs_queue.push(map[bfs_queue.front()][i]);
book[map[bfs_queue.front()][i]] = true;
max_id[map[bfs_queue.front()][i]] = now;
}
}
bfs_queue.pop();
}
}
int main()
{
int n, m, tail, head;
cin >> n >> m;
for (int i = 0; i < m; i++)
{
cin >> tail >> head;
map[head].push_back(tail);
}
for (int i = n; i >= 1; i--)
{
if (!(book[i]))
{
bfs(i);
}
}
for (int i = 1; i < n; i++)
{
cout << max_id[i] << ' ';
}
cout << max_id[n];
return 0;
}