Tarjan缩点+SPFA——缩点

来源:互联网 发布:ubuntu官网下载 编辑:程序博客网 时间:2024/06/16 15:13

题目来源

洛谷P3387缩点

https://www.luogu.org/problem/show?pid=3387


思路

Tarjan+SPFA求DAG上单源最短路模板题

用Tarjan在原图上求SCC 缩点

用缩点之后的SCC建一个有向无环图

SCC权为此SCC内所有点点权和

在新建的DAG上将SCC权视为边权跑SPFA

求SCC[1]到SCC[n]的最长路即为所求答案


代码(C++)

#include <stack>#include <queue>#include <cstdio>#include <bitset>using namespace std;bitset <200010> g,in;    stack<int> s;    queue<int> q;    long long dis[20010],ans=0;int n,m,u,v,cnt=0,num,t=0,S;struct way{int en,ne,ti;}p[200010];int he[20010],dfn[20010],low[20010];int scc[20010],w[20010];void dfs(int pos);inline void add(); void search(int pos);inline void spfa();int main(){    scanf("%d%d",&n,&m);     for(int i=1;i<=n;++i)        scanf("%d",&w[i]);    for(int i=1;i<=m;++i)        scanf("%d%d",&u,&v),add();    num=n;    g=0;    for(int i=1;i<=n;++i)        if(g[i]==0)            search(i);    g=0;    for(int i=1;i<=n;++i)        w[scc[i]]+=w[i];    for(int i=1;i<=n;++i)        if(g[i]==0)            dfs(i);    for(int i=n+1;i<=num;++i)        S=i,spfa();    printf("%lld",ans);    return 0;}inline void spfa(){    int pos,k; in=0;    for(int i=n+1;i<=num;++i)        dis[i]=0;    q.push(S); in[S]=1; dis[S]=w[S];while(!q.empty())    {        pos=q.front();        k=he[pos];in[pos]=0;q.pop();        while(k!=0)        {           if(dis[pos]+w[p[k].en]>dis[p[k].en])            {                dis[p[k].en]=dis[pos]+w[p[k].en];                 if(in[p[k].en]==0)                    q.push(p[k].en);                in[p[k].en]=1;            }            k=p[k].ne;        }            }    for(int i=n+1;i<=num;++i)        if(dis[i]>ans)            ans=dis[i];}void dfs(int pos){    g[pos]=1;    int k=he[pos];    while(k!=0)    {        if(scc[pos]!=scc[p[k].en])        {            if(g[p[k].en]==0)                dfs(p[k].en);            u=scc[pos];            v=scc[p[k].en];            add();        }        k=p[k].ne;    }    return ;}void search(int pos){    g[pos]=1;    s.push(pos);    dfn[pos]=++t;    low[pos]=dfn[pos];    int k=he[pos];    while(k!=0)    {        if(g[p[k].en]==0)        {            search(p[k].en);            if(low[p[k].en]<low[pos])                low[pos]=low[p[k].en];        }        else if(dfn[p[k].en]<low[pos]&&scc[p[k].en]==0)            low[pos]=dfn[p[k].en];        k=p[k].ne;    }    if(low[pos]==dfn[pos])    {        ++num;        while(s.top()!=pos)            scc[s.top()]=num,s.pop();        scc[pos]=num;        s.pop();    }    }inline void add(){    ++cnt;    p[cnt].en=v;    p[cnt].ne=he[u];        he[u]=cnt;}


原创粉丝点击