强连通分量——tarjan

来源:互联网 发布:知道mac地址怎么查ip 编辑:程序博客网 时间:2024/06/06 05:26

洛谷 P2812 校园网络
洛谷 P3387 缩点

洛谷P2812 校园网络

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>using namespace std;struct arr{    int nd,nx;}bot[1100000],d[1100000];int head[20000],h[20000],stack[20000],low[20000],dfn[20000],bl[20000];int rd[20000],cd[20000],tot,cnt,pos,top,scc,size[20000],n;bool instack[20000];inline int read(){    int x=0,w=1;char ch=0;    while(ch!='-'&&(ch<'0'||ch>'9'))  ch=getchar();    if(ch=='-') w=-1,ch=getchar();    while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch-48),ch=getchar();    return x*w; }inline void add(int a,int b){bot[++cnt].nd=b;bot[cnt].nx=head[a];head[a]=cnt;}inline void ad1(int a,int b){d[++tot].nd=b;d[tot].nx=h[a];h[a]=tot;rd[b]++;cd[a]++;}inline void tarjan(int u){    dfn[u]=low[u]=++pos;    stack[++top]=u;instack[u]=true;    for(register int i=head[u];i;i=bot[i].nx) {        int v=bot[i].nd;        if(instack[v]) low[u]=min(dfn[v],low[u]);        if(dfn[v]==0) {tarjan(v);low[u]=min(low[v],low[u]);}    }    if(low[u]==dfn[u]){        ++scc;int t=0;        while(u!=t){ t=stack[top--];instack[t]=false;bl[t]=scc;size[scc]++; }    }}int main(){    n=read();    for(register int i=1;i<=n;++i) {int x=read();while(x){ add(i,x); x=read(); }}    for(register int i=1;i<=n;++i) if(!dfn[i])tarjan(i);    tot=0;    for(register int i=1;i<=n;++i)        for(register int j=head[i];j;j=bot[j].nx){            int v=bot[j].nd;            if(bl[i]!=bl[v]) ad1(bl[i],bl[v]);        }    int ans1=0,ans2=0;    for(register int i=1;i<=scc;++i){//统计一下缩点之后的入度和出度        if(!rd[i]) ans1++;        if(!cd[i]) ans2++;    }    if(scc==1) printf("1\n0");    else printf("%d\n%d",ans1,max(ans1,ans2));} 

洛谷 P3387 缩点

一道模板题,就直接贴代码了。

下面这份代码是先tarjan缩点,再建立一个新图,然后加上SPFA

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>#include<queue>using namespace std;struct arr{    int nd,nx;}bot[1100000],d[1100000];int head[100000],h[100000],stack[100000],low[100000],dfn[100000],bl[100000];int tot,cnt,pos,top,scc,m,n;int c[100000],w[100000];long long dist[100000],f[100000];long long ans;bool instack[100000];inline int read(){    int x=0,w=1;char ch=0;    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();    if(ch=='-') w=-1,ch=getchar();    while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch-48),ch=getchar();    return x*w;}inline void add(int a,int b){bot[++cnt].nd=b;bot[cnt].nx=head[a];head[a]=cnt;}inline void ad1(int a,int b){d[++tot].nd=b;d[tot].nx=h[a];h[a]=tot;}inline void tarjan(int u){     dfn[u]=low[u]=++pos;    stack[++top]=u;instack[u]=true;    for(register int i=head[u];i;i=bot[i].nx){        int v=bot[i].nd;        if(!dfn[v]) { tarjan(v);low[u]=min(low[v],low[u]);}        if(instack[v]) low[u]=min(dfn[v],low[u]);    }     if(dfn[u]==low[u]){        int t=0;++scc;        while(u!=t){ t=stack[top--];instack[t]=false;bl[t]=scc;c[scc]+=w[t];}    }}inline void SPFA(int s){    deque<int>q;    for(int i=1;i<=n;i++) dist[i]=0,f[i]=0;    dist[s]=c[s];f[s]=1;    q.push_back(s);    while(!q.empty()){        int now=q.front();        q.pop_front();        f[now]=0;           for(register int i=h[now];i;i=d[i].nx){             int v=d[i].nd;             if(dist[v]<dist[now]+c[v]){                dist[v]=dist[now]+c[v];                if(!f[v]){                    f[v]=1;                    if(q.empty()||dist[v]>dist[q.front()]) q.push_back(v);                    else q.push_front(v);                }            }          }    }    for(register int i=1;i<=scc;++i)  if(ans<dist[i]) ans=dist[i];}int main(){    n=read(); m=read();    for(register int i=1;i<=n;++i) w[i]=read();    for(register int i=1;i<=m;++i) { int u=read(),v=read(); add(u,v); }    for(register int i=1;i<=n;++i) if(!dfn[i]) tarjan(i);    for(register int i=1;i<=n;++i)        for(register int j=head[i];j;j=bot[j].nx) {            int v=bot[j].nd;            if(bl[i]!=bl[v])                 ad1(bl[i],bl[v]);        }    for(register int i=1;i<=scc;++i)  SPFA(i);    //对于缩点后新建的图跑SPFA    printf("%d\n",ans);}

下面这个代码是先tarjan缩点,建立一个新图,然后加上拓扑排序求最长路。
(本蒟一开始做的时候只有40分,后面请了机房某xxy大佬帮我改了下才过的)

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>#include<queue>using namespace std;struct arr{    int nd,nx;}bot[210000],d[210000];int head[20000],a[20000],h[20000];int rd[20000],cd[20000],dis[20000],topo[30000];int low[20000],dfn[20000],stack[20000],instack[20000],bl[20000],size[20000],c[20000];int n,m,cnt,tot,tt,top,pos,scc,ans;inline int read(){    int x=0,w=1;char ch=0;    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();    if(ch=='-') w=-1,ch=getchar();    while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch-48),ch=getchar();    return x*w;}inline void add(int a,int b) { bot[++cnt].nd=b; bot[cnt].nx=head[a]; head[a]=cnt; }inline void ad1(int a,int b) { d[++tot].nd=b; d[tot].nx=h[a]; h[a]=tot;rd[b]++;cd[a]++;}inline void tarjan(int u){    dfn[u]=low[u]=++pos;    stack[++top]=u; instack[u]=true;    for(register int i=head[u];i;i=bot[i].nx) {        int v=bot[i].nd;        if(!dfn[v]) { tarjan(v);low[u]=min(low[u],low[v]); }        if(instack[v]) {low[u]=min(dfn[v],low[u]);}    }     if(dfn[u]==low[u]) {        int t=0;++scc;        while(t!=u) { t=stack[top--]; instack[t]=false; bl[t]=scc; size[scc]++; c[scc]+=a[t];}    }}inline void tuopu(){    queue<int> q;    for(register int i=1;i<=scc;++i) if(!rd[i]) q.push(i);    while(!q.empty()) {        int u=q.front();q.pop();        topo[++tt]=u;        for(register int i=h[u];i;i=d[i].nx) {            int v=d[i].nd;--rd[v];            if(!rd[v]) q.push(v);        }    }    for(register int i=1;i<=scc;++i) dis[i]=c[i];    int ans=0;    for(int k=1;k<=tt;++k) {        int u=topo[k];        for(register int i=h[u];i;i=d[i].nx) {            int v=d[i].nd;            dis[v]=max(dis[v],dis[u]+c[v]);        }    }    for(register int i=1;i<=scc;++i) ans=max(ans,dis[i]);    printf("%d\n",ans);}int main(){    n=read();m=read();    for(register int i=1;i<=n;++i) a[i]=read();    for(register int i=1;i<=m;++i) {        int u=read(),v=read();        add(u,v);    }    for(register int i=1;i<=n;++i)if(!dfn[i]) tarjan(i);    for(register int i=1;i<=n;++i)        for(register int j=head[i];j;j=bot[j].nx) {            int v=bot[j].nd;            if(bl[i]!=bl[v]) { ad1(bl[i],bl[v]); }//建立新图的时候要注意加入的点是bl[i]和bl[v],不是i和v,错了好几次        }    tuopu();    return 0;} 
原创粉丝点击