题目链接
首先分析,对于有向图中的环我们是一定会经过很多次直到该环无贡献为止,否则只经过一次。那么首先scc缩点处理出环内贡献并且连边建成一颗树,接下来只需要用最短路算法把预先处理的环内贡献作为一个点的点权即可
#include<bits/stdc++.h>
using namespace std;
#define MP 80005
#define MB 200005
stack<int>z;queue<int>q;
int cnt,cntz,cntrz,cntcd,cntrd,M,N,s,ans;
int h[MP],dfn[MP],low[MP],team[MP],rd[MP],cd[MP],dedao[MP];//dedao表示每个强连通分量的蘑菇值
int he[MP],d[MP],vt[MP];bool vst[MP];
struct node1
{
int from,to,next,va;double hui;
}a[MB];
inline int Qxx(int x,int y,int v,double hh)
{
a[++cnt].to=y;
a[cnt].from=x;
a[cnt].va=v;
a[cnt].hui=hh;
a[cnt].next=h[x];
h[x]=cnt;
return 0;
}
inline int Qxx1(int x,int y,int v)//自己yy的缩点建图,就是把h换成he,以防和原h混淆
{
a[++cnt].to=y;
a[cnt].from=x;
a[cnt].va=v;
a[cnt].next=he[x];
he[x]=cnt;
return 0;
}
int jisuan(int x,double y)//计算一条边的蘑菇值
{
int re=0;
while(x)
{
re+=x;
x*=y;
}
return re;
}
void tan(int x)
{
dfn[x]=low[x]=++cntrz;
z.push(x);
for(int i=h[x];i;i=a[i].next)
{
int y=a[i].to;
if(!dfn[y])
{
tan(y);
low[x]=min(low[x],low[y]);
}
else
{
if(!team[y])
{
low[x]=min(low[x],dfn[y]);
}
}
}
if(dfn[x]==low[x])
{
++cntz;
while(1)
{
int y=z.top();z.pop();
team[y]=cntz;
if(y==x)
{
break;
}
}
}
}
void dotarjan()
{
for(int i=1;i<=N;++i)
{
if(!dfn[i])
{
tan(i);
}
}
}
void suodian()
{
int cnt2=cnt;cnt=0;
for(int i=1;i<=cnt2;++i)
{
int x=a[i].from,y=a[i].to;
if(team[x]!=team[y])//x,y在不同的强连通分量
{
int vv=a[i].va;
Qxx1(team[x],team[y],vv);vt[team[x]]=1;
rd[team[y]]++;cd[team[x]]++;
}
else//点x,y在同一强连通分量的话,直接把此强连通分量的蘑菇值加上x到y的边的蘑菇值
{
dedao[team[x]]+=jisuan(a[i].va,a[i].hui);
}
}
}
void SPFA(int x)
{
memset(d,0,sizeof(d));
memset(vst,0,sizeof(vst));
ans=d[x]=dedao[x];//初始化最终答案为起点值,因为可能只有一个强连通分量
q.push(x);vst[x]=1;
while(!q.empty())
{
int k=q.front();
q.pop();
vst[k]=0;
for(int i=he[k]; i; i=a[i].next)
{
int y=a[i].to,z=a[i].va;
if(d[k]+z+dedao[y]>d[y]) //越大越好(正常的SPFA是越小越好)
{
d[y]=d[k]+z+dedao[y];
ans=max(ans,d[y]);
if(!vst[y])
{
vst[y]=1;
q.push(y);
}
}
}
}
}
int main()
{
scanf("%d%d",&N,&M);
for(int i=1;i<=M;i++)
{
int x,y,v;double hg;
scanf("%d%d%d%lf",&x,&y,&v,&hg);
Qxx(x,y,v,hg);
}
cin>>s;
dotarjan();//tarjan求强连通分量
suodian();//缩点的同时随便求每个缩点的蘑菇值
SPFA(team[s]);//跑最长路
printf("%d",ans);
}