前言
這破題目害老子寫了一下午,還好總算寫出來了,用到的是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<bits/stdc++.h>
using namespace std;
const int MAX = 5e5+5;
int M,N;
vector<int> path[MAX];
vector<int> 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<int>& 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<int> 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]) << " " ;
}
}