算法筆記--強連通份量分解

Kosaraju算法php

詳見《挑戰程序設計競賽》p320html

模板:ios

const int N=1e5+5;
int n,m;
vector<int>g[N];
vector<int>rg[N];
vector<int>vs;
bool vis[N];
int cmp[N];

void add_edge(int u,int v)
{
    g[u].pb(v);
    rg[v].pb(u);
} 

void dfs(int u)
{
    vis[u]=true;
    for(int i=0;i<g[u].size();i++)
    if(!vis[g[u][i]])dfs(g[u][i]);
    vs.pb(u);
}

void rdfs(int u,int k)
{
    vis[u]=true;
    cmp[u]=k;
    for(int i=0;i<rg[u].size();i++)
    if(!vis[rg[u][i]])rdfs(rg[u][i],k);
}

int scc()
{
    mem(vis,false);
    vs.clear();
    for(int i=1;i<=n;i++)if(!vis[i])dfs(i);
    
    mem(vis,false);
    int k=0;
    for(int i=vs.size()-1;i>=0;i--)if(!vis[vs[i]])rdfs(vs[i],k++);
    return k; 
}

Tarjan算法模板: 算法

const int N = 1e5 + 5;
vector<int> g[N];
int low[N], dfn[N], stk[N], cmp[N], cnt = 0, top = 0, tot = 0;
bool vis[N];
void tarjan(int u) {
    low[u] = dfn[u] = ++cnt;
    stk[++top] = u;
    vis[u] = true; //標記是否在棧中
    for (int v : g[u]) {
        if(!dfn[v]) {
            tarjan(v);
            low[u] = min(low[u], low[v]);
        }
        else if(vis[v]) low[u] =  min(low[u], dfn[v]);
    }
    if(low[u] == dfn[u]) {
        cmp[u] = ++tot;
        vis[u] = false;
        while(stk[top] != u) {
            cmp[stk[top]] = tot;
            vis[stk[top--]] = false;
        }
        top--;
    }
}

 例題1:POJ 2186 Popular Cowside

代碼:ui

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;
#define ll long long
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))
const int N=1e5+5;
int n,m;
vector<int>g[N];
vector<int>rg[N];
vector<int>vs;
bool vis[N];
int cmp[N];

void add_edge(int u,int v)
{
    g[u].pb(v);
    rg[v].pb(u);
} 

void dfs(int u)
{
    vis[u]=true;
    for(int i=0;i<g[u].size();i++)
    if(!vis[g[u][i]])dfs(g[u][i]);
    vs.pb(u);
}

void rdfs(int u,int k)
{
    vis[u]=true;
    cmp[u]=k;
    for(int i=0;i<rg[u].size();i++)
    if(!vis[rg[u][i]])rdfs(rg[u][i],k);
}

int scc()
{
    mem(vis,false);
    vs.clear();
    for(int i=1;i<=n;i++)if(!vis[i])dfs(i);
    
    mem(vis,false);
    int k=0;
    for(int i=vs.size()-1;i>=0;i--)if(!vis[vs[i]])rdfs(vs[i],k++);
    return k; 
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin>>n>>m;
    int u,v;
    for(int i=0;i<m;i++)cin>>u>>v,add_edge(u,v);
    
    int t=scc();
    int ans=0;
    for(int i=1;i<=n;i++)if(cmp[i]==t-1)ans++,u=i;
    
    mem(vis,false);
    rdfs(u,0);
    
    for(int i=1;i<=n;i++)if(!vis[i])ans=0;
    cout<<ans<<endl; 
    return 0;
} 
View Code

例題2:POJ 1236 Network of Schoolsspa

思路:統計出入度,第一個答案輸出強連通份量入度爲0的個數,第二個答案輸出max(入度爲0個數,出度爲0的個數),若是隻有一個強連通,就是0。.net

代碼:設計

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
#define ll long long
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))

const int N=105;
vector<int>g[N];
vector<int>rg[N];
vector<int>vs;
bool vis[N];
int cmp[N];
int in[N]={0};
int out[N]={0};
int n,a;

void add_edge(int u,int v)
{
    g[u].pb(v);
    rg[v].pb(u);
}

void dfs(int u)
{
    vis[u]=true;
    for(int i=0;i<g[u].size();i++)if(!vis[g[u][i]])dfs(g[u][i]);
    vs.pb(u);
}

void rdfs(int u,int k)
{
    vis[u]=true;
    cmp[u]=k;
    for(int i=0;i<rg[u].size();i++)if(!vis[rg[u][i]])rdfs(rg[u][i],k);
}

int scc()
{
    mem(vis,false);
    vs.clear();
    for(int i=1;i<=n;i++)if(!vis[i])dfs(i);
    
    mem(vis,false);
    int k=0;
    for(int i=vs.size()-1;i>=0;i--)if(!vis[vs[i]])rdfs(vs[i],k++);
    return k;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        while(cin>>a&&a)add_edge(i,a);
    }
    
    int t=scc();
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<g[i].size();j++)
        if(cmp[i]!=cmp[g[i][j]])out[cmp[i]]++,in[cmp[g[i][j]]]++;
    }
    int in1=0,out1=0;
    for(int i=0;i<t;i++)
    {
        //cout<<in[i]<<' '<<out[i]<<endl;
        if(in[i]==0)in1++;
        if(out[i]==0)out1++;
    }
    
    cout<<in1<<endl;
    if(t==1)cout<<0<<endl;
    else cout<<max(in1,out1)<<endl;
    return 0;
} 
View Code

例題3:POJ 1904 King's Quest3d

思路:能結婚的兩我的確定在一個強連通份量裏。

代碼:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector> 
using namespace std;
#define ll long long
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))

const int N=4e3+5;
vector<int>g[N];
vector<int>rg[N];
vector<int>vs;
vector<int>ans;
bool vis[N];
bool mp[N/2][N/2];
int cmp[N];
int n,k,a;

void add_edge(int u,int v)
{
    g[u].pb(v);
    rg[v].pb(u);
}

void dfs(int u)
{
    vis[u]=true;
    for(int i=0;i<g[u].size();i++)if(!vis[g[u][i]])dfs(g[u][i]);
    vs.pb(u);
}

void rdfs(int u,int k)
{
    vis[u]=true;
    cmp[u]=k;
    for(int i=0;i<rg[u].size();i++)if(!vis[rg[u][i]])rdfs(rg[u][i],k);
}

int scc()
{
    mem(vis,false);
    vs.clear();
    for(int i=1;i<=2*n;i++)if(!vis[i])dfs(i);
    
    int k=0;
    mem(vis,false);
    for(int i=vs.size()-1;i>=0;i--)if(!vis[vs[i]])rdfs(vs[i],k++);
    return k;
}

int main()
{
    /*ios::sync_with_stdio(false);
    cin.tie(0);*/
    
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&k);
        while(k--)
        {
            scanf("%d",&a);
            add_edge(i,n+a);
            mp[i][a]=true;
        }
    }
    for(int i=1;i<=n;i++)scanf("%d",&a),add_edge(n+a,i); 
    int t=scc();
    //cout<<t<<endl;
    for(int i=1;i<=n;i++)
    {
        ans.clear();
        for(int j=1;j<=n;j++)
        if(cmp[j+n]==cmp[i]&&mp[i][j])ans.pb(j);
        printf("%d ",ans.size());
        for(int j=0;j<ans.size()-1;j++)printf("%d ",ans[j]);
        printf("%d\n",ans[ans.size()-1]);
    }
    return 0;
} 
View Code

例題4:HDU 1269 迷宮城堡

坑點:當n不爲0時,m爲0不須要退出輸入,由於此時是個非聯通圖。

代碼:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector> 
using namespace std;
#define ll long long
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))

const int N=1e4+5;
vector<int>g[N];
vector<int>rg[N];
vector<int>vs;
bool vis[N];
int cmp[N];
int n,m,u,v;

void add_edge(int u,int v)
{
    g[u].pb(v);
    rg[v].pb(u);
}

void dfs(int u)
{
    vis[u]=true;
    for(int i=0;i<g[u].size();i++)if(!vis[g[u][i]])dfs(g[u][i]);
    vs.pb(u);
}

void rdfs(int u,int k)
{
    vis[u]=true;
    cmp[u]=k;
    for(int i=0;i<rg[u].size();i++)if(!vis[rg[u][i]])rdfs(rg[u][i],k);
}

int scc()
{
    mem(vis,false);
    vs.clear();
    for(int i=1;i<=n;i++)if(!vis[i])dfs(i);
    
    int k=0;
    mem(vis,false);
    for(int i=vs.size()-1;i>=0;i--)if(!vis[vs[i]])rdfs(vs[i],k++);
    return k;
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    
    while(cin>>n>>m&&(n||m))
    {
        for(int i=1;i<=n;i++)g[i].clear(),rg[i].clear();
        while(m--)
        {
            cin>>u>>v;
            add_edge(u,v);
        }
        int t=scc();
        //cout<<t<<endl;
        if(t==1)cout<<"Yes"<<endl;
        else cout<<"No"<<endl;
    }
    return 0;
} 
View Code

例題5:HDU 2767 Proving Equivalences

思路:見例題2。

代碼:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector> 
using namespace std;
#define ll long long
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))

const int N=2e4+5;
vector<int>g[N];
vector<int>rg[N];
vector<int>vs;
bool vis[N];
int cmp[N];
int in[N];
int out[N];
int n,m,u,v;

void add_edge(int u,int v)
{
    g[u].pb(v);
    rg[v].pb(u);
}

void dfs(int u)
{
    vis[u]=true;
    for(int i=0;i<g[u].size();i++)if(!vis[g[u][i]])dfs(g[u][i]);
    vs.pb(u);
}

void rdfs(int u,int k)
{
    vis[u]=true;
    cmp[u]=k;
    for(int i=0;i<rg[u].size();i++)if(!vis[rg[u][i]])rdfs(rg[u][i],k);
}

int scc()
{
    mem(vis,false);
    vs.clear();
    for(int i=1;i<=n;i++)if(!vis[i])dfs(i);
    
    int k=0;
    mem(vis,false);
    for(int i=vs.size()-1;i>=0;i--)if(!vis[vs[i]])rdfs(vs[i],k++);
    return k;
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int t;
    cin>>t;
    while(t--)
    {
        cin>>n>>m;
        for(int i=1;i<=n;i++)g[i].clear(),rg[i].clear();
        mem(in,0);
        mem(out,0);
        while(m--)
        {
            cin>>u>>v;
            add_edge(u,v);
        }
        int t=scc();
        for(int i=1;i<=n;i++)
        {
            for(int j=0;j<g[i].size();j++)
            {
                if(cmp[i]!=cmp[g[i][j]])
                out[cmp[i]]++,in[cmp[g[i][j]]]++;
            }
        }
        int _in=0,_out=0;
        for(int i=0;i<t;i++)
        {
            if(in[i]==0)_in++;
            if(out[i]==0)_out++;
        }
        if(t==1)cout<<0<<endl;
        else cout<<max(_in,_out)<<endl;
    }
    return 0;
} 
View Code

例題6:HDU 1827 Summer Holiday

思路:計算一下聯繫每個強連通的最小話費。

代碼:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector> 
using namespace std;
#define ll long long
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))

const int N=2e4+5;
const int INF=0x3f3f3f3f;
vector<int>g[N];
vector<int>rg[N];
vector<int>vs;
bool vis[N];
int cmp[N];
int in[N];
int out[N];
int mn[N];
int cost[N];
int n,m,u,v;

void add_edge(int u,int v)
{
    g[u].pb(v);
    rg[v].pb(u);
}

void dfs(int u)
{
    vis[u]=true;
    for(int i=0;i<g[u].size();i++)if(!vis[g[u][i]])dfs(g[u][i]);
    vs.pb(u);
}

void rdfs(int u,int k)
{
    vis[u]=true;
    cmp[u]=k;
    for(int i=0;i<rg[u].size();i++)if(!vis[rg[u][i]])rdfs(rg[u][i],k);
}

int scc()
{
    mem(vis,false);
    vs.clear();
    for(int i=1;i<=n;i++)if(!vis[i])dfs(i);
    
    int k=0;
    mem(vis,false);
    for(int i=vs.size()-1;i>=0;i--)if(!vis[vs[i]])rdfs(vs[i],k++);
    return k;
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    while(cin>>n>>m)
    {
        for(int i=1;i<=n;i++)cin>>cost[i];
        for(int i=1;i<=n;i++)g[i].clear(),rg[i].clear();
        mem(in,0);
        mem(out,0);
        mem(mn,INF);
        while(m--)
        {
            cin>>u>>v;
            add_edge(u,v);
        }
        int t=scc();
        for(int i=1;i<=n;i++)
        {
            for(int j=0;j<g[i].size();j++)
            {
                if(cmp[i]!=cmp[g[i][j]])
                out[cmp[i]]++,in[cmp[g[i][j]]]++;
            }
             mn[cmp[i]]=min(mn[cmp[i]],cost[i]);
        }
        
        ll ans=0;
        int cnt=0;
        for(int i=0;i<t;i++)
        {
            if(in[i]==0)ans+=mn[i],cnt++;
        }
        cout<<cnt<<' '<<ans<<endl;
    }
    return 0;
} 
View Code

例題7:POJ 2553 The Bottom of Graph

思路:把英文讀懂了就明白怎麼作了:http://poj.org/showmessage?message_id=162296,其實就是找全部出度爲0的強連通分支

代碼:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector> 
using namespace std;
#define ll long long
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))

const int N=2e4+5;
const int INF=0x3f3f3f3f;
vector<int>g[N];
vector<int>rg[N];
vector<int>vs;
vector<int>ans;
bool vis[N];
int cmp[N];
int in[N];
int out[N];
int n,m,u,v;

void add_edge(int u,int v)
{
    g[u].pb(v);
    rg[v].pb(u);
}

void dfs(int u)
{
    vis[u]=true;
    for(int i=0;i<g[u].size();i++)if(!vis[g[u][i]])dfs(g[u][i]);
    vs.pb(u);
}

void rdfs(int u,int k)
{
    vis[u]=true;
    cmp[u]=k;
    for(int i=0;i<rg[u].size();i++)if(!vis[rg[u][i]])rdfs(rg[u][i],k);
}

int scc()
{
    mem(vis,false);
    vs.clear();
    for(int i=1;i<=n;i++)if(!vis[i])dfs(i);
    
    int k=0;
    mem(vis,false);
    for(int i=vs.size()-1;i>=0;i--)if(!vis[vs[i]])rdfs(vs[i],k++);
    return k;
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    while(cin>>n&&n&&cin>>m)
    {
        for(int i=1;i<=n;i++)g[i].clear(),rg[i].clear();
        mem(in,0);
        mem(out,0);
        for(int i=0;i<m;i++)
        {
            cin>>u>>v;
            add_edge(u,v);
        }
        int t=scc();
        ans.clear(); 
        for(int i=1;i<=n;i++)
        {
            for(int j=0;j<g[i].size();j++)
            if(cmp[i]!=cmp[g[i][j]])
            {
                out[cmp[i]]++;
                in[cmp[g[i][j]]]++;
            }
        } 
        for(int i=1;i<=n;i++)
        {
            if(out[cmp[i]]==0)ans.pb(i);
         } 
         for(int i=0;i<ans.size();i++)
         {
             cout<<ans[i];
             if(i!=ans.size()-1)cout<<' ';
         }
        cout<<endl;
    }
    return 0;
} 
View Code

例題8:POJ 2762 Going from u to v or from v to u?

思路:強連通縮點+拓撲排序,順便學了一波隊列求拓撲排序http://blog.csdn.net/lisonglisonglisong/article/details/45543451

刪邊後入度爲0的點不能超過1個,詳見:http://www.cnblogs.com/scau20110726/archive/2013/05/23/3094495.html

代碼1(鄰接矩陣保存縮點後的DAG):

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))

const int N=1e3+5;
vector<int>g[N];
vector<int>rg[N]; 
vector<int>vs;
bool vis[N];
int cmp[N];
int in[N];
int out[N];
bool newg[N][N];
int n,m,u,v;

void add_edge(int u,int v)
{
    g[u].pb(v);
    rg[v].pb(u);    
}

void dfs(int u)
{
    vis[u]=true; 
    for(int i=0;i<g[u].size();i++)if(!vis[g[u][i]])dfs(g[u][i]);
    vs.pb(u);
}

void rdfs(int u,int k)
{
    vis[u]=true;
    cmp[u]=k;
    for(int i=0;i<rg[u].size();i++)if(!vis[rg[u][i]])rdfs(rg[u][i],k);
}

int scc()
{
    mem(vis,false);
    vs.clear();
    for(int i=1;i<=n;i++)if(!vis[i])dfs(i);
    
    int k=0;
    mem(vis,false);
    for(int i=vs.size()-1;i>=0;i--)if(!vis[vs[i]])rdfs(vs[i],k++);
    return k;
}

void init()
{
    for(int i=1;i<=n;i++)g[i].clear(),rg[i].clear();
    mem(newg,false);
    mem(in,0);
    mem(out,0);
}

bool topo_sort(int t)
{
    queue<int>q;
    int cnt=0;
    for(int i=0;i<t;i++)if(in[i]==0)cnt++,q.push(i);
    if(cnt>1)return false;
    while(!q.empty())
    {
        cnt=0;
        int u=q.front();
        q.pop();
        for(int i=0;i<t;i++)
        {
            if(newg[u][i])
            {
                in[i]--;
                if(in[i]==0)q.push(i),cnt++;
            }
        }
        if(cnt>1)return false;
    }
    return true;
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int t;
    cin>>t;
    while(t--)
    {
        cin>>n>>m;
        init();
        for(int i=0;i<m;i++)
        {
            cin>>u>>v;
            add_edge(u,v);
        }
        int tt=scc();
        for(int i=1;i<=n;i++)
        {
            for(int j=0;j<g[i].size();j++)
            {
                if(cmp[i]!=cmp[g[i][j]])newg[cmp[i]][cmp[g[i][j]]]=true;
            } 
        } 
        for(int i=0;i<tt;i++)
        {
            for(int j=0;j<tt;j++)
            if(newg[i][j])out[i]++,in[j]++;
        }
        if(topo_sort(tt))cout<<"Yes"<<endl;
        else cout<<"No"<<endl;
    }
    return 0;
} 
View Code

代碼2(鄰接表保存縮點後的DAG,有重邊)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))

const int N=1e3+5;
vector<int>g[N];
vector<int>rg[N]; 
vector<int>newg[N];
vector<int>vs;
bool vis[N];
int cmp[N];
int in[N];
int out[N];
int n,m,u,v;

void add_edge(int u,int v)
{
    g[u].pb(v);
    rg[v].pb(u);    
}

void dfs(int u)
{
    vis[u]=true; 
    for(int i=0;i<g[u].size();i++)if(!vis[g[u][i]])dfs(g[u][i]);
    vs.pb(u);
}

void rdfs(int u,int k)
{
    vis[u]=true;
    cmp[u]=k;
    for(int i=0;i<rg[u].size();i++)if(!vis[rg[u][i]])rdfs(rg[u][i],k);
}

int scc()
{
    mem(vis,false);
    vs.clear();
    for(int i=1;i<=n;i++)if(!vis[i])dfs(i);
    
    int k=0;
    mem(vis,false);
    for(int i=vs.size()-1;i>=0;i--)if(!vis[vs[i]])rdfs(vs[i],k++);
    return k;
}

void init()
{
    for(int i=0;i<=n;i++)g[i].clear(),rg[i].clear(),newg[i].clear();
    mem(in,0);
    mem(out,0);
}

bool topo_sort(int t)
{
    queue<int>q;
    int cnt=0;
    for(int i=0;i<t;i++)if(in[i]==0)cnt++,q.push(i);
    if(cnt>1)return false;
    while(!q.empty())
    {
        cnt=0;
        int u=q.front();
        q.pop();
        for(int i=0;i<newg[u].size();i++)
        {
            int v=newg[u][i];
            in[v]--;
            if(in[v]==0)cnt++,q.push(v);
        }
        if(cnt>1)return false;
    }
    return true;
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int t;
    cin>>t;
    while(t--)
    {
        cin>>n>>m;
        init();
        for(int i=0;i<m;i++)
        {
            cin>>u>>v;
            add_edge(u,v);
        }
        int tt=scc();
        for(int i=1;i<=n;i++)
        {
            for(int j=0;j<g[i].size();j++)
            {
                if(cmp[i]!=cmp[g[i][j]])
                {
                    newg[cmp[i]].pb(cmp[g[i][j]]);
                    out[cmp[i]]++;
                    in[cmp[g[i][j]]]++;
                }
            } 
        } 
        
        if(topo_sort(tt))cout<<"Yes"<<endl;
        else cout<<"No"<<endl;
    }
    return 0;
} 
View Code

例題9:POJ 3169 Father Christmas flymouse

思路:強連通縮點成DAG,對於每個入度爲0的節點,dfs求出最大的ans。

代碼:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;
#define ll long long
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))

const int N=3e4+5;
vector<int>g[N];
vector<int>rg[N];
vector<int>ng[N];
vector<int>vs;
bool vis[N];
int a[N];
int in[N];
int cmp[N];
int value[N];
int n,m,u,v;

void init()
{
    for(int i=0;i<=n;i++)g[i].clear(),rg[i].clear(),ng[i].clear();
    mem(in,0);
    mem(value,0);
}

void add_edge(int u,int v)
{
    g[u].pb(v);
    rg[v].pb(u);
}

void dfs(int u)
{
    vis[u]=true;
    for(int i=0;i<g[u].size();i++)if(!vis[g[u][i]])dfs(g[u][i]);
    vs.pb(u); 
}

void rdfs(int u,int k)
{
    vis[u]=true;
    cmp[u]=k;
    for(int i=0;i<rg[u].size();i++)if(!vis[rg[u][i]])rdfs(rg[u][i],k);
} 

int scc()
{
    mem(vis,false);
    vs.clear();
    for(int i=0;i<n;i++)if(!vis[i])dfs(i);
    
    int k=0;
    mem(vis,false);
    for(int i=vs.size()-1;i>=0;i--)if(!vis[vs[i]])rdfs(vs[i],k++);
    return k; 
}

int DFS(int u)
{
    if(!vis[u])
    {
        int t=0;
        vis[u]=true;
        for(int i=0;i<ng[u].size();i++)
        t=max(t,DFS(ng[u][i]));
        value[u]+=t; 
    } 
    return value[u];
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    while(cin>>n>>m)
    {
        init();
        for(int i=0;i<n;i++)cin>>a[i];
        for(int i=0;i<m;i++)cin>>u>>v,add_edge(u,v);
        int t=scc();
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<g[i].size();j++)
            if(cmp[i]!=cmp[g[i][j]])ng[cmp[i]].pb(cmp[g[i][j]]),in[cmp[g[i][j]]]++;
            if(a[i]>0)value[cmp[i]]+=a[i];
        }
        mem(vis,false);
        int ans=0;
        for(int i=0;i<t;i++)if(in[i]==0)ans=max(ans,DFS(i)); 
        cout<<ans<<endl;
        //cout<<value[0]<<endl;
    }
    return 0;
} 
View Code
相關文章
相關標籤/搜索