[題解]圖的遍歷

版權說明:來自洛谷P3916html

題目描述

    給出$N$個點,$M$條邊的有向圖,對於每一個點$v$,求$A(v)$表示從點$v$出發,能到達的編號最大的點。ios

輸入輸出格式:

  輸入格式:

vv,求A(v)A(v)表示從點vv出發,能到達的編號最大的點。
MM

MM

MM

MM

MM

MM
app

    第1 行,2 個整數$N,M$。ide

    接下來$M$行,每行2個整數$U_i,V_i$,表示邊$(U_i,V_i)$。點用$1, 2,\cdots,N$編號。spa

  輸出格式:

    N 個整數$A(1),A(2),\cdots,A(N)$。code

說明

    • 對於60% 的數據,$1 \le N . K \le 10^3$;orm

    • 對於100% 的數據,$1 \le N , M \le 10^5$。htm

思路:

    首先在沒有處理前是有向有環圖,這樣咱們直接DFS是會超時的(固然聽說還有 DFS100次 玄學作法,可是不推薦)。咱們經過tarjan縮點後將其變爲有向無環圖,如圖blog

  

 

那麼後面的事情就很簡單了,咱們首先染色,繼承邊,再經過DFS獲得結果。固然你也能夠記憶化讓時間跑快一點。具體請看代碼繼承

代碼:

  1 #include<iostream>
  2 #include<fstream>
  3 #include<cstring>
  4 #include<stack>
  5 using namespace std;
  6 const int Max_N=1e5+5;
  7 const int Max_E=1e5+5;
  8 
  9 int n,e;
 10 int U[Max_E],V[Max_E],rem[Max_N];
 11 
 12 int tot;
 13 int head[Max_N],Next[Max_E],to[Max_E];
 14 
 15 int Index;
 16 stack<int>sta;
 17 int DFN[Max_N],LOW[Max_N];
 18 bool vis[Max_N];
 19 
 20 int cnt;
 21 int PoiV[Max_N],PoiP[Max_N];
 22 
 23 void Add_Edge(int u,int v)
 24 {
 25     Next[++tot]=head[u];
 26     head[u]=tot;
 27     to[tot]=v;
 28 //    前向星 
 29     return ;
 30 }
 31 void tarjan(int p)
 32 {
 33     vis[p]=1;
 34     sta.push(p);
 35     DFN[p]=LOW[p]=++Index;
 36     register int i;
 37     for(i=head[p];i^0;i=Next[i]){
 38         int u=p,v=to[i];
 39         if(!DFN[v]){
 40             tarjan(v);
 41             LOW[u]=min(LOW[u],LOW[v]);
 42         }
 43         else if(vis[v])
 44             LOW[u]=min(LOW[u],DFN[v]);
 45     }
 46 //    tarjan操做 
 47     if(DFN[p]==LOW[p]){
 48         int pos;
 49         cnt++;
 50         while(pos=sta.top()){
 51             sta.pop();
 52             vis[pos]=0;
 53             PoiP[pos]=cnt;
 54             PoiV[cnt]=max(PoiV[cnt],pos);
 55 //            染色 
 56             if(pos==p)
 57                 break;
 58         }
 59     }
 60     return ;
 61 }
 62 int DFS(int p)
 63 {
 64     if(rem[p]^-1)
 65         return rem[p];
 66     rem[p]=PoiV[p];
 67     register int i;
 68     for(i=head[i];i^0;i=Next[i])
 69         rem[p]=max(rem[p],DFS(to[i]));
 70 //    記憶化搜索獲得答案 
 71     return rem[p];
 72 }
 73 int main()
 74 {
 75     scanf("%d%d",&n,&e);
 76     register int i,j;
 77     for(i=1;i<=e;i++){
 78         scanf("%d%d",&U[i],&V[i]);
 79         Add_Edge(U[i],V[i]);
 80     }
 81     for(i=1;i<=n;i++)
 82         if(!DFN[i])
 83             tarjan(i);
 84 //    tarjan  
 85     tot=0;
 86     memset(head,0,sizeof(head));
 87 //    清空邊 
 88     for(i=1;i<=e;i++)
 89         if(PoiP[U[i]]^PoiP[V[i]])
 90             Add_Edge(PoiP[U[i]],PoiP[V[i]]);
 91 //    這裏好好理解,繼承邊部分 
 92     memset(rem,-1,sizeof(rem));
 93     for(i=1;i<=cnt;i++)
 94         DFS(i);
 95 //    求出縮點後邊的答案 
 96     for(i=1;i<=n;i++){
 97         if(i>1)
 98             printf(" ");
 99         printf("%d",rem[PoiP[i]]);
100     }
101 //    輸出 
102     return 0;
103 }
View Code

 

U_i,V_iUi,Vi,表示邊(U_i,V_i)(Ui,Vi)。點用1, 2,\cdots,N1,2,,N編號。


NN個點,MM條邊的有向圖,對於每一個點vv,求A(v)A(v)表示從點vv出發,能到達的編號最大的點

NN個點,MM條邊的有向圖,對於每一個點vv,求A(v)A(v)表示從點vv出發,能到達的編號最大的點

相關文章
相關標籤/搜索