P3916 图的遍历
题目大意: 给出N个点,M条边的有向图,对于每个点v,求A(v)表示从点v出发,能到达的编号最大的点。
输入:
第一行:
第1 行,2 个整数N,M。
接下来M行,每行2个整数,,表示(,)。点用1,2,……,N编号。
输出:
N 个整数A(1), A(2), ⋯, A(N)。
输入样例:
4 3
1 2
2 4
4 3
输出样例:
4 4 3 4
常规的dfs惨遭超时,也是意料之中的事,然后看了一下题解,思路是反向建变,反向搜索,很巧妙的思路,这就体现了图论问题建图的难处。
就是逆向思维:从大点往小点搜。
一开始不是很理解,调试了一下,例如样例:建好图之后是这样的:
搜索的时候我们从4开始搜索,然后一次dfs中会搜到2,1同时做标记,搜完之后,4, 2, 1它们所能到达编号最大的点就是4,然后再搜3,因为则4已经被搜过,返回即可,即3所能到达最大的点就是3。
将到达的最大点转化为是否可以被当前的最大点到达
所以我们从n到1枚举起点
然后可以发现这样的性质
如果一个点被标记过,也就是说这个点有答案
和该点相连的所有点都被标记过,因此无需搜索这个点。
AC代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 100;
int n, m;
int h[N], e[N], ne[N], idx;
int rem[N];
void add(int a, int b)
{
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
void dfs(int u, int w)
{
rem[u] = w;
for(int i = h[u]; i != -1; i = ne[i])
{
int j = e[i];
if(rem[j]) continue;
dfs(j, w);
}
}
int main()
{
memset(h, -1, sizeof h);
scanf("%d%d", &n, &m);
for(int i = 0; i < m; i++)
{
int a, b;
scanf("%d%d", &a, &b);
add(b, a);
}
for(int i = n; i >= 1; i--)
{
if(rem[i]) continue;
dfs(i, i);
}
for(int i = 1; i <= n; i++) printf("%d ", rem[i]);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端