1. 程式人生 > >2186 Tarjan的模板題..

2186 Tarjan的模板題..

   暑假的時候研究過kosaraju~~A過一些強連通分量..Kosaraju需要做兩個圖, 一個原圖一個是原圖的反圖(每個邊的終點起點反過來..)..正著DFS一次...標記出棧順序..再根據這個出棧順序對反圖進行一次DFS..每次能遍歷到的點就是在一起的強連通分量...

    只說一些要注意的...

    1、Tarjan不是一次Tarjan(1)讓它搜就行了~~要迴圈所有的點...因為1不一定能到所有點..

    2、在DFS迴圈邊來判斷時...首先是看是不是以前訪問過...如果不滿足再來看這個點是不是正在棧中..

    3、不一定在同一強連通分量的電Low值會相等...所以彈棧時的判斷條件不能是說Low相等就彈,而是說彈到一個Low = DFN 的點為止..

    4、彈棧時注意instack,也就是標記點是不是在棧中的要跟著更新... 

    5、可能有的點完全孤立..就是根本沒有邊...所以做完Tarjin後..檢查所有的點是不是都處理過了..如果有沒處理的...直接返回沒有大牛( 0 )..

    這道題是要找所有人都能仰慕到的...也就是除了自己的所有強連通分量裡都能到自己的強連通分量就是一個大牛集合...這裡在做完Tarjan後...要先進行縮點..就是把每個強連通分量都縮成一個點..然後再來判斷...

Program::

//POJ2186 找大牛 Tarjin
#include<iostream>
#include<math.h>
#include<stack>
#define MAXN 15001
using namespace std;
struct pp
{
    int x,y,next;      
}line[MAXN*5],line2[MAXN*5];
int n,m,link[MAXN],tp[MAXN],low[MAXN],instack[MAXN],dfn[MAXN],p,numtp,sum[MAXN];
bool used[MAXN];
stack<int> mystack;
void trajin(int h)
{
   int i,k;  
   low[h]=dfn[h]=++p;  
   used[h]=instack[h]=true; 
   mystack.push(h);   
   k=link[h];
   while (k)
   {
       if (!used[line[k].y])
       {
          trajin(line[k].y);                  
          low[h]=min(low[h],low[line[k].y]);                 
       }else
       if (instack[line[k].y])
       {
          low[h]=min(low[h],dfn[line[k].y]);   //這裡用low[line[k].y]來更新結果同樣正確..但似乎會影響其他的找橋和割的運算
       }
       k=line[k].next;  
   }
   k=h; 
   if (low[k]==dfn[k])
   {           
       numtp++; 
       do
       {
           k=mystack.top();
           mystack.pop();
           instack[k]=true;
           tp[k]=numtp;                
       }while (low[k]!=dfn[k]); 
   }
   return;
}
void dfs(int h)
{
   int k;    
   used[h]=true;
   sum[h]++;
   k=link[h];
   while (k)
   {
      if (!used[line2[k].y]) dfs(line2[k].y);
      k=line2[k].next;   
   }
   return;
}
int getanswer()
{
   int i,ans,cow,k,p;  
   p=0; numtp=0;
   while (!mystack.empty()) mystack.pop();
   memset(used,false,sizeof(used));
   for (i=1;i<=n;i++) 
     if (!used[i]) 
     {
          memset(instack,false,sizeof(instack));
          trajin(i); 
     }
   k=0;
   memset(link,0,sizeof(link));
   for (i=1;i<=m;i++)
    if (tp[line[i].x]!=tp[line[i].y])
    {
        k++;
        line2[k].x=tp[line[i].x];
        line2[k].y=tp[line[i].y];
        line2[k].next=link[line2[k].x];
        link[line2[k].x]=k;                                 
    }
   for (i=1;i<=n;i++)
     if (!tp[i]) return 0;
   p=n;
   n=numtp;
   memset(sum,0,sizeof(sum));
   for (i=1;i<=n;i++)
   {
      memset(used,false,sizeof(used)); 
      dfs(i);
   }
   for (i=1;i<=n;i++) 
     if (sum[i]==n) cow=i;
   ans=0;
   for (i=1;i<=p;i++)
     if (tp[i]==cow) ans++;  
   return ans;
}
int main()
{  
   while (~scanf("%d%d",&n,&m))
   {
       memset(line,0,sizeof(line));
       memset(link,0,sizeof(link));
       memset(tp,0,sizeof(tp));
       int i;
       for (i=1;i<=m;i++) 
       {
           scanf("%d%d",&line[i].x,&line[i].y);
           line[i].next=link[line[i].x];
           link[line[i].x]=i; 
       } 
       printf("%d\n",getanswer());
   }   
   return 0;   
}