算法笔记--强连通分量分解

Kosaraju算法

详见《挑战程序设计竞赛》p320

模板:

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 Cows

代码:

#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 Schools

思路:统计出入度,第一个答案输出强连通分量入度为0的个数,第二个答案输出max(入度为0个数,出度为0的个数),如果只有一个强连通,就是0。

代码:

#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 Quest

思路:能结婚的两个人肯定在一个强连通分量里。

代码:

#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
posted @ 2017-10-08 14:01  Wisdom+.+  阅读(827)  评论(1编辑  收藏  举报