隐藏页面特效

Tarjan&&缩点简析

由于昨天写计蒜客初赛的一道题,看出了是缩点,但一时忘记了另外一个叫什么s...的算法怎么写了,话说我为什么没有回去翻一下自己的blog然后今天就去学了更实用也更强力的Tarjan

Tarjan的思想其实很简单,就是用时间戳(讲得真TM流弊,其实就是DFS访问到的次序)和栈来搞一下

关于Tarjan的写法,我自己也不是很讲得来,大家可以看一下这篇blog

这里讲一下如何用Tarjan来进行缩点

令我们求出的col[i]表示原图中第i个点是哪个强连通分量中的,则我们可以建出新图,方式如下

for (i=1;i<=n;++i) for (j=head[i];j!=-1;j=e[j].next) if (col[i]!=col[e[j].to]) add(col[i],col[e[j].to]);

很玄学?但是它就是正确的,然后我们就得到了缩过点的新图

像有这里有一道模板题:Luogu P3387 【模板】缩点

题意很简单,我们先Tarjan缩点,缩完的点的点权就是它这个强连通分量中的所有点的点权和

然后就是一个DAG(有向无环图)了,我们DP,记搜,拓扑排序都可以

这里我还是习惯性的写了BFS的topo

CODE

#include<cstdio> #include<cstring> using namespace std; const int N=1e4+5,M=1e5+5; struct edge { int to,next; }e[M],ne[M]; int n,m,head[N],nhead[N],a[N],v[N],dfn[N],low[N],stack[N],col[N],dis[N],q[N],ru[N],top,cnt,x,y,tot,sum; bool vis[N]; inline char tc(void) { static char fl[100000],*A=fl,*B=fl; return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++; } inline void read(int &x) { x=0; char ch=tc(); while (ch<'0'||ch>'9') ch=tc(); while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=tc(); } inline void add(int x,int y) { e[++cnt].to=y; e[cnt].next=head[x]; head[x]=cnt; } inline void nadd(int x,int y) { ne[++cnt].to=y; ne[cnt].next=nhead[x]; nhead[x]=cnt; } inline int min(int a,int b) { return a<b?a:b; } inline int max(int a,int b) { return a>b?a:b; } inline void Tarjan(int now) { dfn[now]=low[now]=++tot; stack[++top]=now; vis[now]=1; for (register int i=head[now];i!=-1;i=e[i].next) if (!dfn[e[i].to]) { Tarjan(e[i].to); low[now]=min(low[now],low[e[i].to]); } else { if (vis[e[i].to]) low[now]=min(low[now],dfn[e[i].to]); } if (dfn[now]==low[now]) { col[now]=++sum; v[sum]+=a[now]; vis[now]=0; while (now!=stack[top]) { col[stack[top]]=sum; v[sum]+=a[stack[top]]; vis[stack[top--]]=0; } --top; } } inline int topo(void) { memset(dis,0,sizeof(dis)); register int i; int ans=0; int H=0,T=0; for (i=1;i<=sum;++i) if (!ru[i]) q[++T]=i,dis[i]=v[i],ans=max(dis[i],ans); while (H<T) { int now=q[++H]; for (i=nhead[now];i!=-1;i=ne[i].next) { dis[ne[i].to]=max(dis[ne[i].to],dis[now]+v[ne[i].to]); ans=max(ans,dis[ne[i].to]); if (!(--ru[ne[i].to])) q[++T]=ne[i].to; } } return ans; } int main() { //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout); register int i,j; memset(head,-1,sizeof(head)); memset(e,-1,sizeof(e)); read(n); read(m); for (i=1;i<=n;++i) read(a[i]); for (i=1;i<=m;++i) read(x),read(y),add(x,y); for (i=1;i<=n;++i) if (!dfn[i]) Tarjan(i); memset(nhead,-1,sizeof(head)); memset(ne,-1,sizeof(e)); cnt=0; for (i=1;i<=n;++i) for (j=head[i];j!=-1;j=e[j].next) if (col[i]!=col[e[j].to]) nadd(col[i],col[e[j].to]),++ru[col[e[j].to]]; printf("%d",topo()); return 0; }

__EOF__

本文作者hl666
本文链接https://www.cnblogs.com/cjjsb/p/9032472.html
关于博主:复活的ACM新生,目前爱好仅剩Gal/HBR/雀魂/单机/OSU
版权声明:转载请注明出处
声援博主:欢迎加QQ:2649020702来DD我
posted @   空気力学の詩  阅读(166)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示