Fork me on GitHub

UESTC 901 方老师抢银行 --Tarjan求强连通分量

思路:如果出现了一个强连通分量,那么走到这个点时一定会在强连通分量里的点全部走一遍,这样才能更大。所以我们首先用Tarjan跑一遍求出所有强连通分量,然后将强连通分量缩成点(用到栈)然后就变成了一个DAG(有向无环图),然后跑一遍DFS,不断加上遍历点的权值,如果到了网吧,则更新一遍答案,因为可以出去了。

求强连通分量时,如果low[u] == dfn[u],说明形成了一个新的强连通分量,且根为u。具体求强连通分量见:http://www.cnblogs.com/whatbeg/p/3776422.html

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <stack>
using namespace std;
#define N 100007

struct Edge
{
    int v,next;
}G[3*N],G2[3*N];

int first[3*N],first2[3*N],low[N],dfn[N];
int instk[N],bel[N],coin[N],iswb[N],wb[N],coin2[N];
int tot,tot2,n,m,Time,cnt,P,K,res;
stack<int> stk;

void addedge(Edge *G,int& tot,int *first,int u,int v)
{
    G[tot].v = v;
    G[tot].next = first[u];
    first[u] = tot++;
}

void Tarjan(int u)
{
    low[u] = dfn[u] = ++Time;
    stk.push(u);
    instk[u] = 1;
    for(int i=first[u];i!=-1;i=G[i].next)
    {
        int v = G[i].v;
        if(!dfn[v])   //树边
        {
            Tarjan(v);
            low[u] = min(low[u],low[v]);
        }
        else if(instk[v])  //回边
            low[u] = min(low[u],dfn[v]);
    }
    if(low[u] == dfn[u])
    {
        cnt++;
        int v;
        do
        {
            v = stk.top();
            stk.pop();
            if(iswb[v])
                wb[cnt] = 1;
            instk[v] = 0;
            coin2[cnt] += coin[v];
            bel[v] = cnt;
            if(v == P)
                P = cnt;
        }while(u != v);
    }
}

void dfs(int u,int sum)
{
    sum += coin2[u];
    if(wb[u])
        res = max(res,sum);
    for(int i=first2[u];i!=-1;i=G2[i].next)
    {
        int v = G2[i].v;
        dfs(v,sum);
    }
}

int main()
{
    int i,j,u,v;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        memset(first,-1,sizeof(first));
        memset(first2,-1,sizeof(first2));
        memset(G,0,sizeof(G));
        memset(G2,0,sizeof(G2));
        memset(iswb,0,sizeof(iswb));
        memset(wb,0,sizeof(wb));
        memset(instk,0,sizeof(instk));
        memset(bel,-1,sizeof(bel));
        memset(coin2,0,sizeof(coin2));
        memset(low,0,sizeof(low));
        memset(dfn,0,sizeof(dfn));
        tot = tot2 = 0;
        Time = cnt = 0;
        while(!stk.empty())
            stk.pop();
        for(i=0;i<m;i++)
        {
            scanf("%d%d",&u,&v);
            addedge(G,tot,first,u,v);
        }
        for(i=1;i<=n;i++)
            scanf("%d",&coin[i]);
        scanf("%d",&P);
        scanf("%d",&K);
        for(i=0;i<K;i++)
        {
            scanf("%d",&v);
            iswb[v] = 1;
        }
        for(v=1;v<=n;v++)  //Tarjan求强连通分量
        {
            if(!dfn[v])
                Tarjan(v);
        }
        for(i=1;i<=n;i++)   //重建为一个DAG
        {
            for(j=first[i];j!=-1;j=G[j].next)
            {
                v = bel[G[j].v];
                u = bel[i];
                if(u != v)  //如果相连点不是一个连通分量
                    addedge(G2,tot2,first2,u,v);  //建桥
            }
        }
        res = -1;
        dfs(P,0);
        printf("%d\n",res);
    }
    return 0;
}
View Code

 

posted @ 2014-06-15 10:32  whatbeg  阅读(334)  评论(0编辑  收藏  举报