1. 程式人生 > 實用技巧 >洛谷 P3916 【圖的遍歷】

洛谷 P3916 【圖的遍歷】

這道題綠題有點高了吧...


我一開始的思路就是一個暴力的遍歷,用遞迴加一個記憶化,對於一個點不斷的往下搜尋,然後確定最大的,返回,給上面的節點。就在這個過程中,我們是搜到最大的數然後返回給上層的數,那我們為什麼不直接從大的出發,那麼大的那個數到達的點也就必然能達到這個大的數,這個很好實現,直接反向建圖,從大開始遍歷,遍歷到達的點ans值直接就為這個數。這樣,我寫下了我的第一代程式,超時了,八十分。

#include <bits/stdc++.h>
using namespace std;
int n , m;
int ans[100010] , vis[100010];
vector<int> e[100010];
void dfs(int k , int step){
if(vis[step] || ans[step] >= k) return;
vis[step] = 1;
if(!ans[step] || ans[step] < k) ans[step] = k;
for(int i = 0; i < e[step].size(); i++) dfs(k , e[step][i]);
}
int main(){
cin >> n >> m;
for(int i = 1; i <= m; i++){
int x , y;
cin >> x >> y;
e[y].push_back(x);
}
for(int i = n; i >= 1; i--){
memset(vis , 0 , sizeof(vis));
dfs(i , i);
}
for(int i = 1; i <= n; i++) cout << ans[i] << " ";
return 0;
}

為什麼會超時呢,注意到,我們是從大的開始跑的,從大到小列舉,那麼這個數之前就被遍歷過了的話,現在再次遍歷到時,一定是小於之前遍歷時儲存的數,這樣,就可以寫下最終的程式碼:

#include <bits/stdc++.h>
using namespace std;
int n , m;
int ans[100010] , vis[100010];
vector<int> e[100010];
void dfs(int k , int step){
if(vis[step]) return;
vis[step] = 1;
ans[step] = k;
for(int i = 0; i < e[step].size(); i++) dfs(k , e[step][i]);
}
int main(){
cin >> n >> m;
for(int i = 1; i <= m; i++){
int x , y;
cin >> x >> y;
e[y].push_back(x);
}
for(int i = n; i >= 1; i--) dfs(i , i);
for(int i = 1; i <= n; i++) cout << ans[i] << " ";
return 0;
}