tarjan--缩点
在DAG图种,常会有最长路的寻找,这时就需要经典的缩点建新图了。
网上带佬们的代码花样百出的,着实不太看的来,在我学习的时候愣是东拼西凑地忙活了两小时才做了一个缩点的模板题,可太气了。
最终按我的理解,将解释和代码合一起了。
#include<bits/stdc++.h> #include<algorithm> using namespace std; #define N 202100 #define mt(x) memset(x,0,sizeof x) typedef long long ll; void cn(ll x){cout<<x<<endl;} void cs(string x){cout<<x<<endl;} int n,m; int head[N],num; struct ii { int to,next; int dis; }mp[N]; //链式前向星建图 int a[N],u[N],v[N]; //边权,边 int dfn[N],low[N],vis[N],st[N],cnt,top; //tarjan的时间戳 st为模拟栈的数组,cnt记录tarjan时间,top记录栈 int col[N],val[N],tot; //染色数组,染色后边权数组,染色数 int dis[N]; //spfa最长路dis数组 void init() { mt(head); mt(mp); num=0; } void add(int x,int y,int z) { mp[++num].to=y; mp[num].dis=z; mp[num].next=head[x]; head[x]=num; } void tarjan(int x)//基础tarjan找强连通分量 { dfn[x]=low[x]=++cnt; st[++top]=x; vis[x]=1; for(int i=head[x];i;i=mp[i].next) { int y=mp[i].to; if(!dfn[y]) { tarjan(y); low[x]=min(low[x],low[y]); } else if(vis[y])low[x]=min(low[x],dfn[y]); } if(dfn[x]==low[x]) { ++tot; while(x!=st[top+1])//对于一组强连通分量,进行染色和加边权处理 { int y=st[top--]; vis[y]=0; col[y]=tot; val[tot]+=a[y]; } } } int spfa(int s,int t)//基础spfa最长路 { memset(dis,-0x3f,sizeof dis);mt(vis); dis[s]=0; queue<int>q; q.push(s); while(q.size()) { int x=q.front(); q.pop(); vis[x]=0; for(int i=head[x];i;i=mp[i].next) { int y=mp[i].to; if(dis[y]<dis[x]+mp[i].dis) { dis[y]=dis[x]+mp[i].dis; if(!vis[y]) { q.push(y); vis[y]=1; } } } } return dis[t]; } void solve() { cin>>n>>m; for(int i=1;i<=n;++i)cin>>a[i]; for(int i=1;i<=m;++i) { cin>>u[i]>>v[i]; add(u[i],v[i],0); } for(int i=1;i<=n;++i)//保证连通可以不用循环 if(!dfn[i])tarjan(i); //建新图 init(); int s=0,t=tot+1; for(int i=1;i<=m;++i) { int x=u[i],y=v[i]; if(col[x]!=col[y])add(col[x],col[y],val[col[y]]);//根据染色来建立新图,边权用y } for(int i=1;i<=tot;++i)//未给定出发点则遍历式补建边,如果给定s点位出发点则只需要add(0,col[s],val[col[s]])即可 { add(s,i,val[i]);//补上初始点的边权 add(i,t,0);//保证连通 } cn(spfa(0,t));//一次spfa即可,另外也有根据入度来找spfa的max来确定答案的做法 } int main() { ios::sync_with_stdio(false); cin.tie(0); solve(); return 0; }
此代码也是缩点模板题:https://www.luogu.com.cn/problem/P3387,该题的AC代码
进阶版缩点题:https://www.luogu.com.cn/problem/P3627

#include<iostream> #include<cstring> #include<cstdlib> #include<queue> #include<cmath> #include<map> #include<algorithm> using namespace std; #define N 520210 #define mt(x) memset(x,0,sizeof x) typedef long long ll; void cn(ll x){cout<<x<<endl;} void cs(string x){cout<<x<<endl;} int head[N],num; struct ii { int to,next,dis; }mp[N]; int n,m; int a[N],u[N],v[N]; int s,p,pp[N]; int dfn[N],low[N],vis[N],st[N],cnt,top; int col[N],val[N],tot; int dis[N]; void add(int x,int y,int z) { mp[++num].to=y; mp[num].dis=z; mp[num].next=head[x]; head[x]=num; } void init() { cin>>n>>m; for(int i=1;i<=m;++i) { cin>>u[i]>>v[i]; add(u[i],v[i],0); } for(int i=1;i<=n;++i)cin>>a[i]; cin>>s>>p; for(int i=0;i<p;++i)cin>>pp[i]; } void tarjan(int x) { dfn[x]=low[x]=++cnt; st[++top]=x; vis[x]=1; for(int i=head[x];i;i=mp[i].next) { int y=mp[i].to; if(!dfn[y]) { tarjan(y); low[x]=min(low[x],low[y]); } else if(vis[y])low[x]=min(low[x],dfn[y]); } if(dfn[x]==low[x]) { tot++; while(x!=st[top+1]) { int y=st[top--]; vis[y]=0; col[y]=tot; val[tot]+=a[y]; } } } int spfa(int s,int t) { memset(dis,-0x3f,sizeof dis);mt(vis); dis[s]=0; queue<int>q; q.push(s); vis[s]=1; while(q.size()) { int x=q.front();q.pop(); //cout<<"x=="<<x<<", q.size()=="<<q.size()<<endl; vis[x]=0; for(int i=head[x];i;i=mp[i].next) { int y=mp[i].to; //cout<<"y=="<<y<<endl; if(dis[y]<dis[x]+mp[i].dis) { dis[y]=dis[x]+mp[i].dis; if(!vis[y]) { vis[y]=1; q.push(y); } } } } int ans=0; for(int i=0;i<p;++i)ans=max(ans,dis[col[pp[i]]]); return ans; } void solve() { init(); //cs("读取完成"); for(int i=1;i<=n;++i) if(!dfn[i])tarjan(i); //cs("tarjan"); mt(mp);mt(head);num=0; for(int i=1;i<=m;++i) { int x=u[i],y=v[i]; if(col[x]!=col[y])add(col[x],col[y],val[col[y]]); } int ss=0,t=tot+1; /* 有给定出发点,所以不遍历式建出发边 for(int i=1;i<=tot;++i) { add(s,i,val[i]); add(i,t,0); } */ add(ss,col[s],val[col[s]]); //cs("建图"); cn(spfa(ss,t)); //cs("spfa"); } int main() { ios::sync_with_stdio(false); cin.tie(0); solve(); return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
· 零经验选手,Compose 一天开发一款小游戏!