这破题目害老子写了一下午,还好总算写出来了,用到的是Tarjan算法
不懂Tarjan算法的童鞋,强烈安利B站一位UP主的讲解视频,大神请绕路
像我这种蒟蒻只有看视频听人家讲解才能会,自学算法好苦逼,看博客讲解真他妈费劲
视频链接在此:轻松掌握Tarjan算法,我一遍就完全懂了,强烈安利哦,
建议学会Tarjan算法再来看此题.
原题链接
给出N个点,M条边的有向图,对于每个点v,求A(v)A(v)表示从点vv出发,能到达的编号最大的点。
第1 行,2 个整数N,M。
接下来M行,每行2个整数U,V,表示边(Ui,Vi)。点用1,2,⋯,N编号。
N 个整数A(1),A(2),⋯,A(N)。
输入 #1复制
4 3 1 2 2 4 4 3
输出 #1复制
4 4 3 4
• 对于60% 的数据,1≤N.M≤1e3;
• 对于100% 的数据,1≤N,M≤1e5。
拿到这道题,本以为是个简单的DFS遍历图的问题,提交,10分
仔细一想应该是有局部闭环的,好,那就记忆化再加上每次重新搜索,hhh只有60分
看其他大佬的分析,可以反着写,又看到什么狗屁Tarjan.......就去学Tarjan了
学完Tarjan后........
发现可以把每个强连通分量当成一个点(即缩点),然后做一个映射,重新构建无联通分量的图....
此时重新构建的图就是之前没考虑局部闭环的情况......
知道以上思路+理论后,写代码就很简单了
AC代码如下,有问题各位直接提
#include
using namespace std;
const int MAX = 5e5+5;
int M,N;
vector path[MAX];
vector nwPath[MAX];
//tarjan模板所需的变量
int dfn[MAX],low[MAX];
int timeb;
int inStack[MAX];
//记忆化搜索使用的数组,作为结果保存用于输出
int res[MAX];
//tarjan函数中,用于映射新图中的点所需要的变量
int belong[MAX]; //映射新图,与tcc数组一起发挥作用
int tcc[MAX],countTcc; //记录每个强连通分量的最大结点值
//Tarjan模板
void tarjan(int index,stack& s) {
dfn[index]=low[index]=timeb++;
inStack[index]=true;
s.push(index);
for (int i = 0; i < path[index].size(); ++i) {
if(!dfn[path[index][i]]) {
tarjan(path[index][i],s);
low[index]=min(low[index],low[path[index][i]]);
} else if(inStack[path[index][i]]) {
low[index]=min(low[index],low[path[index][i]]);
}
}
if(low[index]==dfn[index]) {
//为构建新图,对强连通分量做一个映射
tcc[countTcc] = 0;
while (!s.empty()&&s.top()!=index) {
tcc[countTcc]=max(tcc[countTcc],s.top());
belong[s.top()]=countTcc;
inStack[s.top()]=false;
s.pop();
}
belong[s.top()]=countTcc;
tcc[countTcc]=max(tcc[countTcc],s.top());
inStack[s.top()]=false;
s.pop();
countTcc++;
}
}
//用映射点构建新图
void reBuild() {
for (int i = 1; i <= N; ++i) {
for (int j = 0; j < path[i].size(); ++j) {
nwPath[belong[i]].push_back(belong[path[i][j]]);
}
}
}
//简单的记忆化DFS,千万注意搜索的过程中要使用映射后的新图的点
int dfs(int index) {
if(res[index]) return res[index];
res[index]=tcc[index];
for (int i = 0; i < nwPath[index].size(); ++i) {
res[index]=max(dfs(nwPath[index][i]),res[index]);
}
return res[index];
}
int main() {
cin >> N >> M;
while (M--) {
int src,dst;
cin >> src >> dst;
path[src].push_back(dst);
}
stack ss;
timeb=1;
countTcc=0;
for (int i = 1; i <= N; ++i) {
if(!dfn[i]) tarjan(i,ss);
}
reBuild();
for (int i = 1; i <= N; ++i) {
cout << dfs(belong[i]) << " " ;
}
}