缩点

来源:互联网 发布:啤酒配方软件中文版 编辑:程序博客网 时间:2024/04/30 05:26

luogu P3387

一开始蠢蠢地用并查集判断两个强连通分量是否连通,防止重复建边,调了一个晚上才发现有向图不能用并查集判断,如果 a -> b <- c,a 和 c 是不连通的。其实边重复建了也没有影响。

tarjan + 拓扑排序

#include<cstdio>#include<algorithm>using namespace std;const int N = 10005;struct edge{    int from,to,next;}e[10*N];struct edge2{    int to,next;}g[10*N];int head[N],dfn[N],low[N],dfs_clock,color[N],col_num;int sta[N],top,indgr[N],w[N],vi[N],p[N],head2[N],tot,ans;bool isin[N];void tarjan(int u){    dfn[u]=low[u]=++dfs_clock;    sta[++top]=u;    isin[u]=true;    for(int i=head[u];i;i=e[i].next)    {        int v=e[i].to;        if(!dfn[v])        {            tarjan(v);            low[u]=min(low[u],low[v]);        }        else if(isin[v])        {            low[u]=min(low[u],dfn[v]);        }    }    if(low[u]==dfn[u])    {        isin[u]=false;        color[u]=++col_num;        w[col_num]=vi[u];        while(sta[top]!=u)        {            int v=sta[top];            w[col_num]+=vi[v];            isin[v]=false;            color[v]=col_num;            --top;        }        --top;    }}void Add(int from,int to){    g[++tot].next=head2[from];    g[tot].to = to;    head2[from] = tot;}void dp(int u){    p[u]=w[u];    for(int i=head2[u];i;i=g[i].next)    {        int v=g[i].to;        if(!p[v]) dp(v);        p[u]=max(p[u],p[v]+w[u]);    }}int main(){    int n,m;    scanf("%d%d",&n,&m);    for(int i=1;i<=n;++i)    {        scanf("%d",&vi[i]);    }    for(int i=1;i<=m;++i)    {        int u,v;        scanf("%d%d",&u,&v);        e[i].next = head[u];        e[i].from = u;        e[i].to = v;        head[u] = i;    }    for(int i=1;i<=n;++i)    {        if(!dfn[i])        {            dfs_clock=0;            tarjan(i);        }    }    for(int i=1;i<=m;++i)    {        int u=e[i].from,v=e[i].to;        if(color[u]!=color[v])        {            Add(color[u],color[v]);            ++indgr[color[v]];        }    }    top=0;    for(int i=1;i<=col_num;++i)    {        if(indgr[i]==0)        {            sta[++top]=i;            p[i]=w[i];        }    }    while(top)    {        int u=sta[top--];        for(int i=head2[u];i;i=g[i].next)        {            int v=g[i].to;            p[v]=max(p[v],p[u]+w[v]);            if(--indgr[v]==0)                sta[++top]=v;        }    }    for(int i=1;i<=col_num;++i)        ans=max(ans,p[i]);    printf("%d\n",ans);    return 0;}

tarjan + dfs

#include<cstdio>#include<algorithm>using namespace std;const int N = 10005;struct edge{    int from,to,next;}e[10*N];struct edge2{    int to,next;}g[10*N];int head[N],dfn[N],low[N],dfs_clock,color[N],col_num;int sta[N],top,indgr[N],w[N],vi[N],p[N],head2[N],tot,ans;bool isin[N];void tarjan(int u){    dfn[u]=low[u]=++dfs_clock;    sta[++top]=u;    isin[u]=true;    for(int i=head[u];i;i=e[i].next)    {        int v=e[i].to;        if(!dfn[v])        {            tarjan(v);            low[u]=min(low[u],low[v]);        }        else if(isin[v])        {            low[u]=min(low[u],dfn[v]);        }    }    if(low[u]==dfn[u])    {        isin[u]=false;        color[u]=++col_num;        w[col_num]=vi[u];        while(sta[top]!=u)        {            int v=sta[top];            w[col_num]+=vi[v];            isin[v]=false;            color[v]=col_num;            --top;        }        --top;    }}void Add(int from,int to){    g[++tot].next=head2[from];    g[tot].to = to;    head2[from] = tot;}void dp(int u){    p[u]=w[u];    for(int i=head2[u];i;i=g[i].next)    {        int v=g[i].to;        if(!p[v]) dp(v);        p[u]=max(p[u],p[v]+w[u]);    }}int main(){    int n,m;    scanf("%d%d",&n,&m);    for(int i=1;i<=n;++i)    {        scanf("%d",&vi[i]);    }    for(int i=1;i<=m;++i)    {        int u,v;        scanf("%d%d",&u,&v);        e[i].next = head[u];        e[i].from = u;        e[i].to = v;        head[u] = i;    }    for(int i=1;i<=n;++i)    {        if(!dfn[i])        {            dfs_clock=0;            tarjan(i);        }    }    for(int i=1;i<=m;++i)    {        int u=e[i].from,v=e[i].to;        if(color[u]!=color[v])        {            Add(color[u],color[v]);        }    }    for(int i=1;i<=col_num;++i)    {        if(!p[i])        {            dp(i);        }        ans=max(ans,p[i]);    }    printf("%d\n",ans);    return 0;}