我写这个随笔是让我更加理解算法,防止以后出错,因为我今天调Tarjan调了3个多小时,后来还是在大佬的帮忙下调出来了,问题不少
先来看错误的(40pts):
//缩点 //https://www.luogu.com.cn/problem/P3387 #include<bits/stdc++.h> #define int long long using namespace std; const int N=1e6+10,M=1e4+10; int n,m,a[N],res,dist[N],id[N],p[N]; int e[N],ne[N],h[N],w[N],idx; int dfn[N],low[N],_size[N],_stack[N]; int times,top,scc_num; bool vis[N]; void add(int a,int b) { e[idx]=b,ne[idx]=h[a],h[a]=idx++; } void tarjan(int u) { low[u]=dfn[u]=++times; _stack[++top]=u,vis[u]=true; for(int i=h[u];~i;i=ne[i]){ int j=e[i]; if(!dfn[j]) tarjan(j),low[u]=min(low[u],low[j]); else if(vis[j]) low[u]=min(low[u],dfn[j]); } if(low[u]==dfn[u]){ int y; ++scc_num; do{ y=_stack[top--]; vis[y]=false,id[y]=scc_num; if(u==y) break; a[u]+=a[y]; }while(y!=u); } } void topsort() { queue<int>que; for(int i=1;i<=n;i++){ if(id[i]==i&&!p[i]) que.push(i),dist[i]=a[i]; } while(!que.empty()){ int now=que.front(); que.pop(); for(int i=h[now];~i;i=ne[i]){ int j=e[i]; p[j]--,dist[j]=max(dist[j],dist[now]+a[j]); if(p[j]==0) que.push(j); } } } signed main() { cin>>n>>m; memset(h, -1, sizeof h); for(int i=1;i<=n;i++) cin>>a[i]; for(int i=1;i<=m;i++){ int x,y; cin>>x>>y; add(x,y); } for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i); for(int i=1;i<=N;i++) h[i]=-1,ne[i]=e[i]=w[i]=0; for(int i=1;i<=n;i++) for(int j=h[i];~j;j=ne[j]){ int k=e[j]; int x=id[j],y=id[k]; if(x!=y) add(x,y),p[y]++; } topsort(); for(int i=1;i<=n;i++) res=max(res,dist[i]); cout<<res<<endl; return 0; }
修正之后:
//本题基本思想,将连通图用tarhan缩成DAG图然后跑一遍最长路就可以 //下面有几个注意点 #include<bits/stdc++.h> using namespace std; const int N=1e5+10; int n,m,res,p[N],dist[N],a[N]; int e[N],ne[N],h[N],idx,money[N]; //int _e[N],_ne[N],_h[N],_idx; int dfn[N],low[N],_stack[N],id[N]; int scc_num,times,top; vector<int>mp[N]; bool vis[N]; void add(int a,int b) { e[idx]=b,ne[idx]=h[a],h[a]=idx++; } void tarjan(int u) { low[u]=dfn[u]=++times; _stack[++top]=u,vis[u]=true; for(int i=h[u];~i;i=ne[i]){ int j=e[i]; if(!dfn[j]) tarjan(j),low[u]=min(low[u],low[j]); else if(vis[j]) low[u]=min(low[u],dfn[j]); } if(low[u]==dfn[u]){ int y; ++scc_num; do{ y=_stack[top--]; vis[y]=false,money[scc_num]+=a[y],id[y]=scc_num; //链表都是新得了,我们得到的DAG是图是全新的 //所以此时的变量时SCC_NUM,我们要开一个新的数组记录边权值,这里用money }while(y!=u); } } void topsort() { queue<int>que; for(int i=1;i<=scc_num;i++) if(!p[i]) que.push(i),dist[i]=money[i]; while(!que.empty()){ int now=que.front(); que.pop(); for(int i=0;i<mp[now].size();i++){ int j=mp[now][i]; p[j]--,dist[j]=max(dist[j],dist[now]+money[j]); if(p[j]==0) que.push(j); } } } int main() { cin>>n>>m; memset(h,-1,sizeof h); for(int i=1;i<=n;i++) cin>>a[i]; for(int i=1;i<=m;i++){ int x,y; cin>>x>>y; add(x,y); } for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i); for(int i=1;i<=n;i++) for(int j=h[i];~j;j=ne[j]){ int k=e[j]; int x=id[i],y=id[k];//这里不是id[j],而是id[i],因为我们要求的是第i个点与其所有邻点是否相通 if(x!=y) mp[x].push_back(y),p[y]++; //注意点一,一定要重新再建一个链表,而且之前的那个链表不能重置 } topsort(); for(int i=1;i<=n;i++) res=max(res,dist[i]); cout<<res<<endl; return 0; }
标签:Tarjan,idx,vis,int,++,dfn,low From: https://www.cnblogs.com/o-Sakurajimamai-o/p/17615133.html