P2656 采蘑菇 - Tarjan缩点+SPFA
Posted dprswdr
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P2656 采蘑菇 - Tarjan缩点+SPFA相关的知识,希望对你有一定的参考价值。
思路:当我们走到一个环时,可以重复绕圈将这个环上的所有蘑菇采完。这启发我们用Tarjan缩点,将整个环的边权缩到一个点上,然后SPFA跑最长路即可。
AC Code:
#include<cstdio> #include<cstring> #include<algorithm> #include<queue> using namespace std; const int N=80000+100,M=200000+100; struct node{ int to,nxt,w; double p; }e[M]; int head[N],tot; void add(int u,int v,int w,double p){ e[++tot]=(node){v,head[u],w,p}; head[u]=tot; } struct ed{ int u,v,w; double p; }E[M]; int dfn[N],low[N],idx; int s[N],top; bool ins[N]; int col[N],cnt,colv[N]; void tarjan(int u){ dfn[u]=low[u]=++idx; s[++top]=u;ins[u]=1; for(int i=head[u];i;i=e[i].nxt){ int v=e[i].to; if(!dfn[v]){ tarjan(v); low[u]=min(low[u],low[v]); } else if(ins[v]) low[u]=min(low[u],dfn[v]); } if(dfn[u]==low[u]){ cnt++; while(s[top]!=u){ col[s[top]]=cnt; ins[s[top]]=0; top--; } col[u]=cnt; ins[u]=0; top--; } } int dis[N]; bool vis[N]; queue<int>q; void SPFA(int s){ q.push(col[s]);vis[col[s]]=1; while(q.size()){ int u=q.front();q.pop();vis[u]=0; for(int i=head[u];i;i=e[i].nxt){ int v=e[i].to; if(dis[v]<dis[u]+e[i].w+colv[v]) { dis[v]=dis[u]+e[i].w+colv[v]; if(!vis[v]){ q.push(v);vis[v]=1; } } } } } int main(){ int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=m;i++){ int u,v,w; double p; scanf("%d%d%d%lf",&u,&v,&w,&p); add(u,v,w,p); E[i]=(ed){u,v,w,p}; } int s; scanf("%d",&s); tarjan(s); tot=0; memset(head,0,sizeof(head)); memset(e,0,sizeof(e)); for(int i=1;i<=m;i++){ int u=E[i].u,v=E[i].v,w=E[i].w; double p=E[i].p; if(col[u]!=col[v]) add(col[u],col[v],w,0); else{ //若某条边在一个scc中,将其边权和全部加入所属的scc的点权中 while(w){ colv[col[u]]+=w; w*=p; } } } //初始每个缩后的点的最短路为其点权 for(int i=1;i<=cnt;i++){ dis[i]=colv[i]; } SPFA(s); int ans=-(1<<30); //ans=max{从源点到每个点的最长路} for(int i=1;i<=cnt;i++){ ans=max(ans,dis[i]); } printf("%d",ans); return 0; }
以上是关于P2656 采蘑菇 - Tarjan缩点+SPFA的主要内容,如果未能解决你的问题,请参考以下文章