圖的遍歷
題目描述
給出 N 個點, M條邊的有向圖,對於每個點 v ,求 A(v) 表示從點 v 出發,能到達的編號最大的點。
輸入輸出格式
輸入格式:
第1 行,2 個整數 N,M 。
接下來 M行,每行2個整數 Ui,Vi ,表示邊 (Ui,Vi) 。點用 1,2,⋯,N 編號。
輸出格式:
N 個整數 A(1),A(2),⋯,A(N) 。
輸入輸出樣例
說明
• 對於60% 的數據,1≤N.K≤103 ;
• 對於100% 的數據,1≤N,M≤105 。
分析:
一開始看到這題想到的還是Tarjan縮點+dfs,但是還有更加巧妙的方法可以更簡便地AC。
首先分析,直接搜索肯定是有錯誤的,因為會有環,如果數據故意卡的話是很容易卡死的(因為遍歷順序是與存邊順序有關的,而且又是有向圖,直接搜可能會導致WA掉)
當然環可以縮點去掉。但是這樣太麻煩了,不如換個思路。
因為要求的是可以到達的編號最大的點,那么我們可以反向建邊,問題就轉換為求可以到達該點的最大編號的點,那么就從n到1反向遍歷,直接一邊dfs即可。當然要注意,該圖不一定是個連通圖。具體看代碼。
Code:
#include<bits/stdc++.h> using namespace std; const int N=1e5+7; int n,m,head[N],size,ans[N]; struct Node{int to,next;}edge[N]; inline int read() { char ch=getchar();int num=0;bool flag=false; while(ch<'0'||ch>'9'){if(ch=='-')flag=true;ch=getchar();} while(ch>='0'&&ch<='9'){num=num*10+ch-'0';ch=getchar();} return flag?-num:num; } inline void add(int x,int y) { edge[++size].to=y; edge[size].next=head[x]; head[x]=size; } inline void dfs(int u,int sum) { if(ans[u])return; ans[u]=sum; for(int i=head[u];i!=-1;i=edge[i].next){ dfs(edge[i].to,sum);} } int main() { n=read();m=read();int x,y; memset(head,-1,sizeof(head)); memset(ans,0,sizeof(ans)); for(int i=1;i<=m;i++){ x=read();y=read();add(y,x);} for(int i=n;i>=1;i--) if(!ans[i])dfs(i,i); for(int i=1;i<=n;i++) printf("%d ",ans[i]); return 0; }