Description
小胖和ZYR要去ESQMS森林采蘑菇。
ESQMS森林间有N个小树丛,M条小径,每条小径都是单向的,连接两个小树丛,上面都有一定数量的蘑菇。小胖和ZYR经过某条小径一次,可以采走这条路上所有的蘑菇。由于ESQMS森林是一片神奇的沃土,所以一条路上的蘑菇被采过后,又会长出一些新的蘑菇,数量为原来蘑菇的数量乘上这条路的“恢复系数”,再下取整。
比如,一条路上有4个蘑菇,这条路的“恢复系数”为0.7,则第一~四次经过这条路径所能采到的蘑菇数量分别为4,2,1,0.
现在,小胖和ZYR从S号小树丛出发,求他们最多能采到多少蘑菇。
对于30%的数据,N<=7,M<=15
另有30%的数据,满足所有“恢复系数”为0
对于100%的数据,N<=80,000,M<=200,000,0.1<=恢复系数<=0.8且仅有一位小数,1<=S<=N.
Input
第一行,N和M
第2……M+1行,每行4个数字,分别表示一条小路的起点,终点,初始蘑菇数,恢复系数。
第M+2行,一个数字S
Output
一个数字,表示最多能采到多少蘑菇,在int32范围内。
Solution
强联通分量缩点。
记录每个 SCC 内部把所有的边都压榨完之后的权值和 sze[]
然后拓扑跑最长路即可。
upd:第一遍 wa 是因为用了一种自作聪明的在 Tarjan 过程就求 sze 的做法,但是是错的,因为一个包含 n 个点的 SCC 不一定只有 n 条边。
第二遍 wa 是因为数据有自环,所以在计算 sze 的时候不能根据起点和终点求,而是要遍历每条边。
Code
// By YoungNeal
#include<queue> #include<cstdio> #include<cstring> #include<iostream> #define N 80005 #define M 200005 int maxn; int n,m,s; bool in[N]; int sze[N]; int dis[N]; int deg[N]; int head2[N]; int stk[N],top; int cnt,sum,tot; int c[N],head[N]; int dfn[N],low[N]; struct Edge{ int to,nxt,dis,js; }edge[M],edge2[M]; void add(int x,int y,int z,int k){ edge[++cnt].to=y; edge[cnt].nxt=head[x]; edge[cnt].dis=z; edge[cnt].js=k; head[x]=cnt; } void add_c(int x,int y,int z){ edge2[++cnt].to=y; edge2[cnt].nxt=head2[x]; edge2[cnt].dis=z; head2[x]=cnt; } void tarjan(int now){ dfn[now]=low[now]=++sum; stk[++top]=now;in[now]=1; for(int i=head[now];i;i=edge[i].nxt){ int to=edge[i].to; if(!dfn[to]) tarjan(to),low[now]=std::min(low[now],low[to]); else if(in[to]) low[now]=std::min(low[now],low[to]); } if(dfn[now]==low[now]){ int y;tot++; do{ y=stk[top--]; c[y]=tot,in[y]=0; }while(y!=now); } } int calc(int a,double b){ int ans=0; while(a){ ans+=a; a*=b; } return ans; } void toposort(){ std::queue<int> topo; for(int i=1;i<=tot;i++) dis[i]=-2e9; dis[c[s]]=sze[c[s]]; maxn=dis[c[s]]; for(int i=1;i<=tot;i++){ if(!deg[i]) topo.push(i); } while(topo.size()){ int u=topo.front();topo.pop(); for(int i=head2[u];i;i=edge2[i].nxt){ int to=edge2[i].to; dis[to]=std::max(dis[to],dis[u]+sze[to]+edge2[i].dis); deg[to]--; if(!deg[to]) topo.push(to); } } for(int i=1;i<=tot;i++) maxn=std::max(maxn,dis[i]); } signed main(){ scanf("%d%d",&n,&m); for(int a,b,c,i=1;i<=m;i++){ double x; scanf("%d%d%d%lf",&a,&b,&c,&x); int js=calc(c,x); add(a,b,c,js); } scanf("%d",&s); cnt=0; for(int i=1;i<=n;i++){ if(!dfn[i]) tarjan(i); } for(int x=1;x<=n;x++){ for(int i=head[x];i;i=edge[i].nxt){ int to=edge[i].to; if(c[x]!=c[to]) continue; sze[c[to]]+=edge[i].js; } } for(int x=1;x<=n;x++){ for(int i=head[x];i;i=edge[i].nxt){ int to=edge[i].to; if(c[x]==c[to]) continue; add_c(c[x],c[to],edge[i].dis); deg[c[to]]++; } } toposort(); printf("%d ",maxn); return 0; }